为什么 JVM 的本机内存跟踪报告会报告线程内竞技场区域的内存使用率如此之高

swo*_*ody 5 java memory-management

我遇到一个问题,我有一个 Java 应用程序,在内存不足后偶尔会被 Linux 中的 oom Killer 杀死。我监控了堆,它没有增长。事实上,它甚至从未达到 允许的Xmx最大值768MB

因此,我通过启用本机内存跟踪-XX:NativeMemoryTracking=summary。然后,我运行我的应用程序,获取基线,然后等到它开始消耗内存,此时我用来jcmd <pid> VM.native_memory detail.diff生成以下报告。

Native Memory Tracking:

Total: reserved=16894180KB +14703341KB, committed=15330936KB +14896985KB

-                 Java Heap (reserved=786432KB, committed=450048KB +129536KB)
                            (mmap: reserved=786432KB, committed=450048KB +129536KB)

-                     Class (reserved=1185329KB +110708KB, committed=156657KB +128180KB)
                            (classes #23288 +19829)
                            (malloc=11825KB +2164KB #27117 +23990)
                            (mmap: reserved=1173504KB +108544KB, committed=144832KB +126016KB)

-                    Thread (reserved=16825159KB +16803246KB, committed=16825159KB +16803246KB)
                            (thread #47 +24)
                            (stack: reserved=47288KB +25472KB, committed=47288KB +25472KB)
                            (malloc=153KB +82KB #240 +120)
                            (arena=16777717KB +16777692 #92 +48)

-                      Code (reserved=260509KB +9756KB, committed=63625KB +56100KB)
                            (malloc=10909KB +9756KB #14012 +11850)
                            (mmap: reserved=249600KB, committed=52716KB +46344KB)

-                        GC (reserved=39135KB +15KB, committed=37831KB +307KB)
                            (malloc=10399KB +15KB #629 +478)
                            (mmap: reserved=28736KB, committed=27432KB +292KB)

-                  Compiler (reserved=890284KB +890139KB, committed=890284KB +890139KB)
                            (malloc=55KB +41KB #334 +258)
                            (arena=890229KB +890098 #8 +5)

-                  Internal (reserved=13299KB +3377KB, committed=13299KB +3377KB)
                            (malloc=13267KB +3377KB #26649 +21418)
                            (mmap: reserved=32KB, committed=32KB)

-                    Symbol (reserved=32729KB +27117KB, committed=32729KB +27117KB)
                            (malloc=28565KB +24400KB #285695 +250801)
                            (arena=4163KB +2717 #1)

-    Native Memory Tracking (reserved=13011KB +12136KB, committed=13011KB +12136KB)
                            (malloc=367KB +241KB #5803 +3803)
                            (tracking overhead=12644KB +11895KB)

-               Arena Chunk (reserved=18014398506330278KB -3153154KB, committed=18014398506330278KB -3153154KB)
                            (malloc=18014398506330278KB -3153154KB)
Run Code Online (Sandbox Code Playgroud)

从报告中我可以看到使用的内存量显着增加committed=15330936KB +14896985KB,但这不是在堆中。

看来这发生在线程使用的内存中。堆栈本身看起来很正常,因为每个线程堆栈都应该如此,因此1024KB对于47288KB47 个线程来说是合理的。

Thread (reserved=16825159KB +16803246KB, committed=16825159KB +16803246KB)
                            (thread #47 +24)
                            (stack: reserved=47288KB +25472KB, committed=47288KB +25472KB)
                            (malloc=153KB +82KB #240 +120)
                            (arena=16777717KB +16777692 #92 +48) 
Run Code Online (Sandbox Code Playgroud)

特别是,它报告竞技场增加了+16777692。是什么原因导致了这种情况?或者这不是一个问题?从我在网上看到的其他报告(包括其他 stackoverflow 问题)来看,arena 内存使用量从未如此高。

此外,Arena Chunk 本身的预留大小也很大。这是正常的吗?如果不正常的话是什么原因导致这种异常?

以下公开的 JDK 错误JDK-8164293似乎报告了 JVM 本身的内存泄漏,那么我是否会遇到此错误?

Onk*_*nki 1

我们遇到了类似的问题,该问题尚未解决,仍在调查中。您可以看到下面的链接, java 8 中 javaw 进程的私有字节数增加

但我仍然想在这里分享我的分析。

1) 这个arena的增加没有映射到堆。所以很明显不是java代码的问题。从这个角度来看,它看起来像是 JNI 代码问题或 java api 内部的本机泄漏。因此,跟踪您的 JNI 代码,看看您是否正在关闭所有 malloc 调用,并对所有本机 java 对象使用 deleteLocalRef 和 deleteGlobalRef。

2)检查是否只有在java更新后才出现此问题。如果是,则检查您在代码中使用的 jni.h 和相关文件。是从java8.

3)如果仍然没有运气,那么使用像 Jemalloc 这样的工具,它可以告诉你导致最大泄漏的方法名称。看来这是linux下最好的工具了。

查看此链接:https://gdstechnology.blog.gov.uk/2015/12/11/using-jemalloc-to-get-to-the-bottom-of-a-memory-leak/

4)您可以使用VADump等工具查看哪个dll消耗最多的内存。

我们的调查仍在进行中,如果有结果我会立即通知您。请您也在此更新您的进展情况。