调用JNI时引起堆外内存泄漏问题的排查
问题表现:
最近项目中有通过JNI调用linux下动态库的场景,该动态库被多线程并发高频调用时,会造成操作系统内存的急剧上升,最终java进程会被强制下掉。
排查过程:
通过top命令查看进程对资源的使用情况,多线程并发下,物理内存的增长很快,使用完后开始消耗swap空间,当swap空间消耗到一定程度(大概30-40%)时,进程被linux操作系统OOM-KILLER强制下掉,通过/var/log/messages可看到相关日志。
通过JDK自带的jvisualvm控制台查看资源使用情况,堆内存使用正常,并没有出现OOM的问题。并发线程运行也正常。
通过上述排查,怀疑调用的动态库(.so文件)可能有问题,故找到该动态库对应的c文件,审查处理逻辑,在审查中发现,该动态库中有个方法,在开始时,使用malloc函数申请了内存空间,但处理完成后,并未调用free函数对内存空间进行释放,导致并发处理时,内存使用一直处在上升状态。
找到问题后,修改此C程序,重新编译并生成动态库,测试,问题解决。
经验总结:
遇到JNI调用动态库的场景时,首先要评审动态库的处理逻辑,有条件最好评审动态库的代码,以便及早发现此类问题。