为何无交换分区时Java NMT提交内存远小于RSS?
NMT无法追踪的内存增长场景
以下是几种可能导致Java进程RSS持续增长但NMT统计提交内存稳定的场景:
- JVM内部原生内存盲区:部分JVM版本的NMT未覆盖所有内部原生内存分配,比如GC的临时缓冲区、JIT编译器的缓存结构、或者JVM与系统交互的底层数据结构,这些内存由JVM直接通过系统调用分配,未被NMT的追踪钩子捕获。
- 非标准Native内存分配:除了主JNI库外,若依赖的第三方组件(如监控代理、字节码增强工具的Native部分)使用
malloc、mmap等原生系统调用分配内存,而非通过Unsafe.allocateMemory或ByteBuffer.allocateDirect这类NMT可追踪的接口,这部分内存会被计入RSS但不会出现在NMT统计中。 - 系统层面的内存映射:进程加载的系统共享库、系统自动创建的匿名内存映射,或是通过系统调用创建的文件映射(如
tmpfs),这些内存属于进程RSS范畴,但不在JVM NMT的统计范围内。 - 线程附属内存未被统计:NMT会统计线程栈,但线程的内核态栈、Linux下的线程本地存储(TLS)扩展区域等附属内存结构,可能未被纳入NMT提交内存统计。若进程运行中频繁创建/销毁线程,这部分内存的累加可能导致RSS与NMT数值差扩大。
- NMT统计粒度限制:默认的NMT统计(
-XX:NativeMemoryTracking=summary)可能遗漏部分特殊内存区域,即使开启detail模式,仍存在部分无法追踪的分配场景,比如某些调试、诊断相关的JVM内存分配。 - 系统内存回收延迟:即使JVM已释放原生内存,操作系统可能因内存压力较低未及时回收这些内存页,导致RSS中保留已释放的内存。虽然页面错误数为0,但这种延迟回收若伴随频繁的分配-释放循环,也会造成RSS持续高于NMT统计值。
内容的提问来源于stack exchange,提问作者Di Sarra George
相关产品推荐
相关产品推荐

