解释jemaloc数据可能在堆外泄漏

Elr*_*roy 2 java jvm

我在2周前开始搜索不断增长的java内存.我使用以下命令来防止堆增长过多,并进行一些调试.

我正在使用oracle java 8在Ubuntu 16.04上运行,因为openjdk 8没有调试符号我需要让jemaloc提供正确的数据

-XX:NativeMemoryTracking=detail -XX:+UseG1GC -XX:+UseStringDeduplication -Xms64m -Xmx256m -XX:MaxMetaspaceSize=128m -Xss256k
Run Code Online (Sandbox Code Playgroud)

如你所见,我的Xmx设置为256米.但是top目前我的流程显示为1.1G

在使用JProfiler和JVisualVm I以及我在google上可以找到的许多其他东西后,我得出的结论是,这必然是一个堆外问题.

经过多次搜索,我遇到了jemaloc,我读到的关于它的文章似乎很有希望.但是现在解释这些数据我遇到了一些问题.并找出如何指出我的问题的根源.

最高内存使用率

jemaloc图

本机内存跟踪数据

Native Memory Tracking:

Total: reserved=1678MB, committed=498MB
-                 Java Heap (reserved=256MB, committed=256MB)
                            (mmap: reserved=256MB, committed=256MB)

-                     Class (reserved=1103MB, committed=89MB)
                            (classes #14604)
                            (malloc=3MB #32346)
                            (mmap: reserved=1100MB, committed=85MB)

-                    Thread (reserved=26MB, committed=26MB)
                            (thread #53)
                            (stack: reserved=26MB, committed=26MB)

-                      Code (reserved=261MB, committed=96MB)
                            (malloc=17MB #17740)
                            (mmap: reserved=244MB, committed=79MB)

-                        GC (reserved=1MB, committed=1MB)
                            (mmap: reserved=1MB, committed=1MB)

-                  Internal (reserved=6MB, committed=6MB)
                            (malloc=6MB #48332)

-                    Symbol (reserved=19MB, committed=19MB)
                            (malloc=16MB #168491)
                            (arena=4MB #1)

-    Native Memory Tracking (reserved=5MB, committed=5MB)
                            (tracking overhead=4MB)
Run Code Online (Sandbox Code Playgroud)

apa*_*gin 11

检查进程内存映射

本机内存跟踪的帐户只有Java虚拟机的结构,但它并不能算内存映射文件也不是由共享库(包括Java类库的本地代码)分配本机内存.此外,NMT不会跟踪malloc- 标准libc分配器的任何内部碎片.

首先,要分析Java进程的堆外使用情况,请查看其完整的内存映射:

pmap -X <pid>
Run Code Online (Sandbox Code Playgroud)

这将阐明映射文件或匿名区域是使用内存.

更改标准分配器

如果您看到多个匿名区域多达64 MB,这可能是malloc竞技场的标志.众所周知,Libc malloc 在某些系统上存在过多的虚拟内存使用问题.在这种情况下,使用jemalloctcmalloc作为直接替换(即使没有分析功能)也可能成为解决方案.

配置本机分配

不幸的是,jemalloc profiler对Java一无所知; 图形在最后一个本机函数处中断,因此输出可能看起来令人困惑.在你的情况下,jemalloc暗示问题可能与课程加载有关System.loadLibrary,但是如果没有完整的图片则很难确定.

Async-profiler允许在Java上下文中跟踪本机分配.跑

./profiler.sh -d <duration> -e malloc -f malloc.svg <pid>
Run Code Online (Sandbox Code Playgroud)

这将产生一个火焰图形malloc调用,例如:

Malloc火焰图

这只是一个演示如何java.util.zip.GZIPOutputStream成为本机内存分配源的示例.当然,你的情况会有所不同.

请注意,malloc调用本身并不意味着内存泄漏.例如,可以分配内存,然后在不久之后释放.该图只是一个提示在哪里查看.

为了找到RSS增加的位置,您可能需要跟踪mprotectmmap调用.这可以通过async-profiler以类似的方式完成:

./profiler.sh -d <duration> -e mprotect -f mprotect.svg <pid>
./profiler.sh -d <duration> -e mmap -f mmap.svg <pid>
Run Code Online (Sandbox Code Playgroud)

注意代理库

我注意到cbClassPrepareclassTrack_processUnloads在你的jemalloc图中发挥作用.这意味着您正在使用jdwp调试代理.这绝对是内存分配过多的原因 - 我以前看过内存泄漏jdwp.任何其他代理库启用过-agentlib,-agentpath-javaagent选择也是一个犯罪嫌疑人,因为他们的本机内存使用不是由JVM跟踪.