我想知道通过‑XX:NativeMemoryTracking=summary启用NMT的真正/典型开销是什么(我想要的完整命令选项是-XX:+UnlockDiagnosticVMOptions ‑XX:NativeMemoryTracking=summary ‑XX:+PrintNMTStatistics)
我在任何地方都找不到很多信息--无论是在博客上还是在官方文档上。医生说:
注意:启用NMT会导致5% -10%的性能开销。
但是他们没有说明哪种模式会产生这种性能开销(包括摘要和细节)?这种开销实际上是(CPU,内存,.)。在本机内存跟踪指南中,他们声称:
启用NMT将导致JVM性能下降5-10 %,NMT的内存使用会将2个机器单词作为malloc头添加到所有malloc内存中。NMT也会跟踪NMT内存的使用情况。
但同样,摘要模式和细节模式都是这样吗?
我想要的基本上是,为生产应用程序永久添加‑XX:NativeMemoryTracking=summary是否安全(类似于连续的JFR记录),以及潜在的成本。到目前为止,在我们的应用程序上测试这个时,我没有发现有什么不同,但很难
是否有权威的信息来源,包含有关此性能开销的更多详细信息?有人有为生产应用程序永久启用此功能的经验吗?
发布于 2022-07-29 14:12:16
本地内存跟踪的开销显然取决于应用程序分配本机内存的频率。通常,在Java应用程序中,这种情况并不常见,但情况可能有所不同。由于您已经尝试过并且没有注意到性能差异,所以您的应用程序显然也不是一个例外。
在summary模式下,本机内存跟踪大致完成以下操作:
malloc请求增加2个机器字(16个字节);free上递减)对应于给定内存类型的计数器;malloc和free之外,它还处理虚拟内存预留和新领域分配的更改,但这些更改甚至比malloc/free调用更少。因此,对我来说,开销是相当小的;5-10%肯定是一个很大的高估(对于收集和存储堆栈跟踪的detail模式来说,这些数字是有意义的,这很昂贵,但summary不这样做)。
当许多线程同时分配/释放本机内存时,原子计数器的更新可能成为瓶颈,但同样,这更像是一种极端情况。简而言之,如果您测量了一个实际的应用程序,并且没有注意到任何退化,那么在生产中启用NMT摘要可能是安全的。
发布于 2022-07-30 12:49:48
免责声明:我的答案是基于JDK 18,我所写的大部分内容对于旧版本都是有效的。当你有疑问的时候,你需要自己来衡量。
背景:
NMT跟踪通过Direct缓冲区完成的热点VM内存使用和内存使用情况。基本上,它连接到malloc/free和mmap/munmap调用并进行计算。
它不跟踪其他JDK内存使用情况( hotspot VM外部)或第三方库的使用情况。这在这里很重要,因为它使NMT行为在某种程度上可以预测。Hotspot试图通过malloc避免细粒度的分配。相反,它依赖于自定义内存管理器,如Arenas、代码堆或Metaspace。
因此,对于大多数应用程序来说,hotspot中的mallocs/mmap并不是那么“热”,也不是很大。
我将把重点放在malloc/free上,因为它们的数量远远超过mmap/munmap的数量:
内存成本:
这里,(1)完全矮小(2)和(3)。因此,摘要模式和细节模式之间的内存开销并不显著。
请注意,甚至(1)也可能没有那么重要,因为基础libc分配器已经规定了可能大于(纯分配大小+ 16字节malloc报头)的最小分配大小。因此,需要测量NMT内存开销实际转化为RSS增加的程度。
总共有多少内存开销,这意味着无法回答,因为JVM内存成本通常由堆大小决定。因此,将RSS与NMT成本进行比较几乎是毫无意义的。但是仅举一个例子,对于具有1GB预触摸堆NMT内存开销的spring memory来说,大约是0.5%。
根据我的经验,NMT内存开销仅在病理情况下或在导致JVM进行大量细粒度分配的角落情况下才起作用。如果一个人做了疯狂的类加载量。但通常情况下,您希望启用NMT,以查看正在发生的事情。
业绩成本:
NMT确实需要一些同步。在摘要模式中,它原子地增加每个malloc/free上的计数器。
在详细模式中,它做了更多的工作:
这需要更多的周期。散列映射是无锁的,但仍然使用原子操作进行修改。它看起来很昂贵,特别是如果hotspot处理了来自不同线程的许多错误。情况到底有多糟?
最坏情况例子
微基准,64 malloc分配(通过Unsafe.allocateMemory())由100个并发线程完成,在一台24核心机器上:
NMT off: 6 secs
NMT summary: 34 secs
NMT detail: 46 secs看上去很疯狂。然而,这在实践中可能并不重要,因为这不是现实生活的例子。
弹簧启动,平均10次:
NMT off: 3.79 secs
NMT summary: 3.79 secs (+0%)
NMT detail: 3.91 secs (+3%)所以,这里,没那么糟。摘要模式的成本实际上在测试噪声中消失了。
文艺复兴,哲学家的基准
有趣的例子,因为这做了大量的同步,导致许多对象监视器被膨胀,而这些是错误的:
平均基准分数:
NMT off: 4697
NMT summary: 4599 (-2%)
NMT detail: 4190 (-11%)有些介于另外两个例子之间。
结论
没有明确的答案。
内存和性能成本都取决于JVM进行了多少分配。
对于正常的行为良好的应用程序来说,这个数字很小,但是在病态情况下(例如JVM错误),以及在一些由用户程序引起的情况下(例如,大量的类加载或同步),这个数目可能很大。可以肯定的是,你需要衡量一下自己。
https://stackoverflow.com/questions/73126185
复制相似问题