我想知道通过启用 NMT 时的真实/典型开销是多少\xe2\x80\x91XX:NativeMemoryTracking=summary(我之后的完整命令选项是-XX:+UnlockDiagnosticVMOptions \xe2\x80\x91XX:NativeMemoryTracking=summary \xe2\x80\x91XX:+PrintNMTStatistics)
我在任何地方都找不到太多信息 - 无论是在 SO、博客文章还是官方文档上。\n文档说:
\n\n\n注意:启用NMT会导致5%-10%的性能开销。
\n
但他们没有说明哪种模式预计会有这种性能开销(摘要和详细信息?)\n以及这种开销到底是什么(CPU、内存……)。\n在本机内存跟踪指南中,他们声称:
\n\n\n启用 NMT 将导致 JVM 性能下降 5-10%,并且 NMT 的内存使用会向所有 malloc 内存添加 2 个机器字作为 malloc 标头。NMT 内存使用情况也会被 NMT 跟踪。
\n
但同样,对于摘要模式和详细模式来说都是如此吗?
\n我所追求的基本上是为生产应用程序永久添加是否安全\xe2\x80\x91XX:NativeMemoryTracking=summary(类似于连续JFR 记录)以及潜在成本是多少。\n到目前为止,在我们的应用程序上测试这一点时,我没有发现差异但很难
是否有包含有关此性能开销的更多详细信息的权威信息源?\n是否有人有为生产应用程序永久启用此功能的经验?
\nTho*_*efe 16
免责声明:我的答案基于 JDK 18。我编写的大部分内容应该对旧版本有效。如有疑问,您需要自己测量。
NMT 跟踪热点 VM 内存使用情况和通过直接字节缓冲区完成的内存使用情况。基本上,它连接到 malloc/free 和 mmap/munmap 调用并进行记帐。
它不跟踪其他 JDK 内存使用情况(热点 VM 之外)或第三方库的使用情况。这在这里很重要,因为它使 NMT 的行为在某种程度上是可预测的。Hotspot 尝试避免通过 malloc 进行细粒度分配。相反,它依赖于自定义内存管理器,例如 Arenas、代码堆或元空间。
因此,对于大多数应用程序来说,来自热点的 malloc/mmap 并不是那么“热门”,并且 malloc 的数量也不是那么大。
在本文的其余部分中,我将重点关注 malloc/free,因为它们的数量迄今为止超过了 mmap/munmap 的数量:
在这里,(1)完全使(2)和(3)相形见绌。因此,摘要模式和详细模式之间的内存开销并不大。
请注意,即使 (1) 也可能没有那么重要,因为底层 libc 分配器已经规定了可能大于(纯分配大小 + 16 字节 malloc 标头)的最小分配大小。因此,需要测量有多少 NMT 内存开销实际上转化为 RSS 增加。
这意味着总共有多少内存开销无法回答,因为 JVM 内存成本通常由堆大小决定。因此,将 RSS 与 NMT 成本进行比较几乎没有意义。但仅举个例子,对于具有 1GB 预修饰堆 NMT 内存的 Spring Petclinic,开销约为 0.5%。
根据我的经验,NMT 内存开销仅在病态情况或导致 JVM 执行大量细粒度分配的极端情况下才重要。例如,如果一个人进行了大量的类加载。但通常在这些情况下,您希望启用 NMT,以查看发生了什么。
NMT 确实需要一些同步。它以摘要模式自动增加每个 malloc/free 上的计数器。
在详细模式下,它可以执行更多操作:
这需要更多的周期。哈希图是无锁的,但仍然通过原子操作进行修改。它看起来很昂贵,特别是当热点从不同线程进行许多 malloc 时。到底有多糟糕?
微基准测试,在 24 核机器上由 100 个并发线程完成 64 mio malloc 分配(通过 Unsafe.allocateMemory()):
NMT off: 6 secs
NMT summary: 34 secs
NMT detail: 46 secs
Run Code Online (Sandbox Code Playgroud)
这看起来很疯狂。然而,在实践中这可能并不重要,因为这不是现实生活中的例子。
NMT off: 3.79 secs
NMT summary: 3.79 secs (+0%)
NMT detail: 3.91 secs (+3%)
Run Code Online (Sandbox Code Playgroud)
所以,在这里,还不错。摘要模式的成本实际上在测试噪音中消失了。
有趣的例子,因为这做了很多同步,导致许多对象监视器膨胀,并且这些对象监视器被分配:
平均基准分数:
NMT off: 4697
NMT summary: 4599 (-2%)
NMT detail: 4190 (-11%)
Run Code Online (Sandbox Code Playgroud)
介于其他两个示例之间。
没有明确的答案。
内存和性能成本都取决于 JVM 执行的分配次数。
对于正常表现良好的应用程序来说,这个数字很小,但在病态情况(例如 JVM bug)以及由用户程序引起的某些极端情况下(例如,大量类加载或同步),这个数字可能很大。要真正确定,您需要衡量一下自己。
apa*_*gin 11
本机内存跟踪的开销显然取决于应用程序分配本机内存的频率。通常,这在 Java 应用程序中并不常见,但情况可能有所不同。由于您已经尝试过并且没有注意到性能差异,因此您的应用程序显然也不例外。
在该summary模式下,Native Memory Tracking大致做了以下几件事:
malloc将JVM 中的每个请求增加2 个机器字(16 字节);free)与给定内存类型对应的计数器;malloc和之外free,它还处理虚拟内存预留的更改和新区域的分配,但这些甚至比malloc/free调用更不频繁。所以,对我来说,开销相当小;5-10% 绝对是一个很大的高估(这些数字对于收集和存储堆栈跟踪的模式来说是有意义的detail,这种模式很昂贵,但summary并不能做到这一点)。
当许多线程同时分配/释放本机内存时,原子计数器的更新可能成为瓶颈,但同样,这更像是一种极端情况。简而言之,如果您测量了真实的应用程序并且没有发现任何性能下降,那么您可能可以安全地在生产中启用 NMT 摘要。
| 归档时间: |
|
| 查看次数: |
2542 次 |
| 最近记录: |