JVM NMT输出中arena项与Arena Chunk块的含义是什么
1. Symbol内存块下malloc与arena统计项的区别,以及NMT单独统计arena的原因
首先要避开一个常见命名误区:NMT中统计的arena项,和glibc malloc底层实现的arena内存池完全是两个独立概念,只是命名重合,二者的统计逻辑完全不同:
malloc=xxMB项:记录JVM直接通过glibc提供的malloc/calloc/realloc接口申请、未走JVM内部内存池管理的零散内存,后面的#xxxx数字是该分类下累计的内存分配次数。比如你看到的Symbol分类下41MB malloc内存,就是JVM为存储类名、方法名、常量字符串等符号对象,逐次调用malloc申请的零散内存总和。- 同分类下的
arena=xxMB项:记录JVM自身实现的arena区域分配器占用的内存,和glibc的arena机制没有任何关联。JVM自研的arena分配器逻辑是:先批量从操作系统申请一大块连续内存(底层仍会调用glibc malloc或mmap),之后JVM内部直接在这块内存上切分小块,分配给同生命周期的对象使用,生命周期结束后整块内存一次性释放,不需要逐块调用free,分配效率远高于逐次申请。你看到的Symbol下2MB arena、后面跟着的#1,就是JVM为符号表批量预留、走自身arena分配器管理的内存块,代表当前该分类下共持有1个arena分配实例。
NMT单独拆分arena统计的原因很简单:
glibc的arena是C库层面为降低多线程锁竞争实现的内部内存池,对上层运行的JVM是完全透明的。NMT的实现原理是hook JVM层面的内存申请、释放系统调用,只能感知JVM向glibc申请了多少内存、释放了多少内存,无法感知glibc拿到内存之后的内部切分、缓存逻辑,自然不可能统计到glibc内部arena的占用。NMT单独列出的arena统计,仅对应JVM自己实现的那套arena分配器的内存占用,和glibc的arena机制无关。
2. 独立Arena Chunk内存块的含义
这个分类统计的是JVM自研arena分配器的全局预留块开销:
JVM的arena分配器向系统申请内存时,会按固定大小的chunk(块)批量申请。这些chunk中,已经分配给具体子系统(比如Symbol存储、JIT编译、JNI调用等场景)的部分,会计入对应子系统分类的arena统计项;还未绑定到具体使用场景、处于全局空闲预留状态的chunk,以及arena chunk本身的元数据开销,会被统一统计到独立的Arena Chunk分类下。
你输出中看到的6MB属于JVM正常的预留开销,只要这个数值没有持续无限制上涨,就不存在内存泄漏问题。
补充排查提示:如果NMT统计的总committed内存,和top/ps等工具看到的进程实际RSS差距较大,一块常见的差值来源就是glibc arena的内部碎片——JVM释放内存给glibc后,glibc没有将内存归还给操作系统,而是留在自身arena池中做缓存,这部分内存NMT无法统计,属于C库层面的内存占用。
内容的提问来源于stack exchange,提问作者ruanhao

