Java 1.8生产环境Native内存泄漏(Internal分类)排查求助
Java 1.8生产环境Native内存泄漏(Internal分类)排查求助
我现在遇到一个非常棘手的问题——运行在Java 1.8.0_302上的应用出现了Native内存泄漏,而且这个问题只在生产环境出现,哪怕用相同的Jar包、配置、JDK版本,在其他环境完全复现不出来。
因为保密原因,我没法提供Jar包或者最小复现案例,下面是目前掌握的问题细节和我已经做过的排查:
- 应用以Windows服务形式运行在Windows服务器上
- 进程内存每天以约400MB的速度增长,而且看起来是无界的,最高涨到过6GB,最后不得不重启
- 进程堆内存上限是512MB,实际基本从没达到过,平均维持在300MB左右
- 用JConsole确认过Non-Heap的各个部分(比如元空间、压缩类空间)都没问题,整个Non-Heap最多也就150MB
- 手动触发GC也无法释放那些额外占用的内存
- 启用了NMT(Native Memory Tracking)的摘要模式,发现问题出在标记为Internal的部分——这是唯一持续增长的区域,通过malloc分配内存
- 想切换到NMT的详细模式进一步排查,但详细模式里也看不到具体申请内存的函数/类名,根本没法定位到具体是哪个类或方法在占用内存
- 进程的线程数稳定在40左右,最多45个
- 抓取过线程dump,没有发现线程占用异常内存的情况
- 应用用到了Netty,但我觉得不是Netty的问题:已经开启了Netty的泄漏检测,还分析过堆dump里的所有ByteBuffer实例,没找到指向Netty的泄漏线索
- 用VisualVM检查过堆dump里的DirectByteBuffer、ByteBuffer等类似实例的最大占用,也没发现异常
- 同一台生产服务器上还有几个同应用的不同配置实例,它们都没有泄漏问题。目前能想到的区别是,出问题的实例多引入了一个包:
com.microsoft.graph 6.3.0版本 - 应用用到了自定义类加载器和一些JNI调用,但其他实例也用了完全相同的类加载器和JNI文件/调用,没有出现问题,所以应该不是这部分的锅
现在我本来想通过逐个禁用应用模块来排查根源,但生产环境不能长时间停服或者禁用部分功能,这条路走不通。
目前我已经卡壳了,不知道该怎么进一步诊断,甚至都不清楚NMT里的Internal分类到底包含哪些内容。如果有人能给一些可能的原因方向,或者进一步排查的思路,我会非常感激!之后有新发现我会及时更新这个帖子。
备注:内容来源于stack exchange,提问作者Riley




