这些Java本地内存是从哪里分配的?

9

JDK版本是热点8u_45

我研究了我的Java进程的本地内存。本地内存甚至比堆消耗更多的空间。然而,有许多本地内存块使我感到困惑。例如,pmap -x的结果:

00007f8128000000   65508   25204   25204 rw---    [ anon ]
00007f812bff9000      28       0       0 -----    [ anon ]
00007f812c000000   65508   24768   24768 rw---    [ anon ]
00007f812fff9000      28       0       0 -----    [ anon ]
00007f8130000000   65508   25532   25532 rw---    [ anon ]
00007f8133ff9000      28       0       0 -----    [ anon ]
00007f8134000000   65524   22764   22764 rw---    [ anon ]
00007f8137ffd000      12       0       0 -----    [ anon ]
00007f8138000000   65508   26456   26456 rw---    [ anon ]
00007f813bff9000      28       0       0 -----    [ anon ]
00007f813c000000   65508   23572   23572 rw---    [ anon ]
00007f813fff9000      28       0       0 -----    [ anon ]
00007f8140000000   65520   23208   23208 rw---    [ anon ]
00007f8143ffc000      16       0       0 -----    [ anon ]
00007f8144000000   65512   23164   23164 rw---    [ anon ]
00007f8147ffa000      24       0       0 -----    [ anon ]
00007f8148000000   65516   23416   23416 rw---    [ anon ]
00007f814bffb000      20       0       0 -----    [ anon ]
00007f814c000000   65508   23404   23404 rw---    [ anon ]
00007f814fff9000      28       0       0 -----    [ anon ]
00007f8150000000   65512   24620   24620 rw---    [ anon ]
00007f8153ffa000      24       0       0 -----    [ anon ]
00007f8154000000   65536   23976   23976 rw---    [ anon ]
00007f8158000000   65508   23652   23652 rw---    [ anon ]
00007f815bff9000      28       0       0 -----    [ anon ]
00007f815c000000   65508   23164   23164 rw---    [ anon ]
00007f815fff9000      28       0       0 -----    [ anon ]
00007f8160000000   65508   23344   23344 rw---    [ anon ]
00007f8163ff9000      28       0       0 -----    [ anon ]
00007f8164000000   65508   24052   24052 rw---    [ anon ]
00007f8167ff9000      28       0       0 -----    [ anon ]
00007f8168000000  131052   48608   48608 rw---    [ anon ]
00007f816fffb000      20       0       0 -----    [ anon ]
00007f8170000000   65516   23056   23056 rw---    [ anon ]
00007f8173ffb000      20       0       0 -----    [ anon ]
00007f8174000000   65516   26860   26860 rw---    [ anon ]
00007f8177ffb000      20       0       0 -----    [ anon ]
00007f8178000000   65508   23360   23360 rw---    [ anon ]
00007f817bff9000      28       0       0 -----    [ anon ]
00007f817c000000   65536   24856   24856 rw---    [ anon ]
00007f8180000000   65512   23272   23272 rw---    [ anon ]
00007f8183ffa000      24       0       0 -----    [ anon ]
00007f8184000000   65508   23688   23688 rw---    [ anon ]
00007f8187ff9000      28       0       0 -----    [ anon ]
00007f8188000000   65512   24024   24024 rw---    [ anon ]
00007f818bffa000      24       0       0 -----    [ anon ]
00007f818c000000   65508   25020   25020 rw---    [ anon ]
00007f818fff9000      28       0       0 -----    [ anon ]
00007f8190000000   65512   22868   22868 rw---    [ anon ]
00007f8193ffa000      24       0       0 -----    [ anon ]
00007f8194000000   65508   24156   24156 rw---    [ anon ]
00007f8197ff9000      28       0       0 -----    [ anon ]
00007f8198000000   65508   23684   23684 rw---    [ anon ]

有许多占用约64M内存的块。

我使用jcmd pid VM.native_memory detail来跟踪这些内存块。然而,我在jcmd结果中列出的所有内存范围中都找不到这些块。

此外,我注意到一篇文章提到了glibc malloc中的arena效应 Java 8和Linux虚拟内存。然而,这些块似乎与线程池不同,因为1.模式是rw---而不是-----2. arena线程池只影响虚拟内存。它无法解释这些过多的RSS。

我使用gdb来跟踪分配的内存。

dump binary memory mem.bin from to

mem.bin.1 图片描述

mem.bin.2 图片描述

mem.bin.3

图片描述 mem.bin.4

图片描述

这些图片展示了大约30个内存块。

几天后,我使用Google perf工具来跟踪堆分配情况。发现如下结果: 图片描述

它显示:zip解压缩占用了近2G内存。我猜测这可能与某些编译问题有关。

我已经阅读了这个问题:https://bugs.openjdk.java.net/browse/JDK-8164293。这与我的问题有关吗?

那么,我该如何跟踪这些内存块的来源呢?


这是什么类型的Java进程?你在做任何互操作吗? - Jorn Vernee
我的意思是本地互操作。我想到的这个想法是,在虚拟机之外分配的内存不会通过jcmd显示,但会通过pmap显示。 - Jorn Vernee
这是一个好观点。我会找到它们并回复你。@JornVernee - chenatu
你可以尝试使用NMT与pmap -x进行比较。此外,还可以查看直接字节缓冲区的堆转储。 - the8472
这绝对与编译无关。正如我所说,ZipInputStream/JarInputStream是此类泄漏的常见来源。例如,应用程序调用Class.getResourceAsStream但没有关闭结果流。创建堆转储以查看谁持有java.util.zip.Inflater对象。 - apangin
显示剩余4条评论
1个回答

6

使用jemalloctcmalloc - 它们都有内置的分配分析器,可以帮助确定分配来源。

Java进程可能由于多种原因而使用过多的本机内存。流行的原因包括

  • 直接字节缓冲区
  • Unsafe.allocateMemory分配的内存
  • 未关闭的资源(例如ZipInputStream
  • 其他本机库

请注意,NativeMemoryTracking不会显示本机库消耗的内存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接