解释jemaloc数据可能发生堆外泄漏

时间:2018-12-02 00:02:42

标签: java jvm

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

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

port

您可以看到我的Xmx设置为256m。但是-XX:NativeMemoryTracking=detail -XX:+UseG1GC -XX:+UseStringDeduplication -Xms64m -Xmx256m -XX:MaxMetaspaceSize=128m -Xss256k 当前显示我的进程为1.1G

使用JProfiler和JVisualVm我以及在Google上可以找到的许多其他东西后,我得出的结论是,这肯定是一个堆外问题。

经过大量搜索,我发现top,而且我读到的有关该文章的前景似乎很好。但是我现在在解释这些数据时遇到一些问题。并找出如何找出问题的根源。

top memory usage

jemaloc graph

本机内存跟踪数据

jemaloc

1 个答案:

答案 0 :(得分:8)

检查进程内存映射

本机内存跟踪仅说明Java虚拟机的结构,但不计算内存映射文件或共享库分配的本机内存(包括Java类库的本机代码)。此外,NMT不跟踪标准libc分配器malloc的任何内部碎片。

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

pmap -X <pid>

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

更改标准分配器

如果您看到多个匿名区域变为64 MB,则可能是malloc舞台的标志。已知Libc malloc在某些系统上与excessive virtual memory usage有问题。在这种情况下,使用jemalloctcmalloc作为即插即用替换(即使没有概要分析功能)也可能成为解决方案。

配置文件本机分配

不幸的是,jemalloc探查器对Java一无所知。该图在最后一个本机函数处中断,因此输出可能会造成混淆。在您的情况下,jemalloc建议问题可能与类加载和System.loadLibrary有关,但是如果没有完整图片,很难确定。

Async-profiler允许在Java上下文中跟踪本机分配。运行

./profiler.sh -d <duration> -e malloc -f malloc.svg <pid>

这将产生malloc个呼叫中的Flame Graph,例如:

Malloc Flame Graph

这只是一个示例,展示了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>

注意代理库

我注意到您的jemalloc图中有cbClassPrepareclassTrack_processUnloads函数。这意味着您正在使用jdwp调试代理。这绝对是内存分配过多的原因-我以前在jdwp中曾见过内存泄漏。通过-agentlib-agentpath-javaagent选项启用的任何其他代理库也是可疑的,因为JVM不会跟踪其本机内存使用情况。

相关问题