实际开发场景中应该有发现Java应用程序会消耗比设置-Xms和-Xmx更多的内存,究其原因其实是因为JVM中除了大家熟知的堆内存外,还有所谓的非堆内存(Non-Heap Memory),详细来看,非堆内存包括方法区和Java虚拟机内部做处理或优化所需的内存。
从图上可以看到JVM内存部分,除了堆内存外还有方法区,包括线程栈,常量池,方法和构造函数代码等。方法区在逻辑上是堆的一部分,但在HotSpot中是堆外存储的,不同虚拟机可能实现有所不同。
Native Memory Tracking (NMT)
NMT,全称为Native Memory Tracking,是Java 8u40版本引入的一项功能,用于跟踪JVM本身在本地内存中的内存使用情况。我们可以使用 NMT 来追踪了解 JVM 的内存使用详情(即上图中的 JVM Memory 部分),帮助我们排查内存增长与内存泄漏相关的问题。
Native Memory Tracking 主要是用来通过在 JVM 向系统申请内存的时候进行埋点实现的。
Native Memory Tracking 默认是不开启的,并且无法动态开启(因为这是埋点采集统计的,如果可以动态开启那么没开启的时候的内存分配没有记录无法知晓,所以无法动态开启),目前只能通过在启动 JVM 的时候通过启动参数开启。
NativeMemoryTracking参数使用
回到本文要说的 NativeMemoryTracking参数,这个参数用于开启和配置NMT的。要开启配置和在需要时进行查看,需要配合jcmd的命令来实现。
配置启动NMT参数
通过设置 JVM 启动参数来开启:
-XX:NativeMemoryTracking=[off | summary | detail]
关于参数选项的解释如下
off | 不跟踪 JVM 本地内存使用情况。如果不指定 -XX:NativeMemoryTracking 选项则默认为off。 |
summary | 仅跟踪 JVM 子系统(如:Java heap、class、code、thread等)的内存使用情况。 |
detail | 除了通过 JVM 子系统跟踪内存使用情况外,还可以通过单独的 CallSite、单独的虚拟内存区域及其提交区域来跟踪内存使用情况。 |
使用 jcmd <pid> VM.native_memory 查看
开启之后,我们可以通过 jcmd 命令去查看 Native Memory Tracking 的信息,即
jcmd <pid> VM.native_memory