Java 堆转储和堆分析后的堆大小不同

2022-09-03 07:43:49

我正在经历内存泄漏,这里有一些细节。

在泄漏后,

  • 顶部显示 50GB 内存作为住宅
  • 堆转储文件大小为 25GB
  • eclipse MAT Analyzer告诉我堆大小是10GB

在泄漏前,

  • 顶部显示 30GB 内存作为住宅
  • 堆转储文件大小为 20GB
  • eclipse MAT Analyzer告诉我堆大小是10GB

我很惊讶顶部,堆转储大小和实际堆大小之间的差异。我猜顶部和堆之间的区别在于垃圾收集器堆和本机堆区域的可能性。但是,为什么堆转储文件大小和实际堆大小(来自 eclipse MAT 分析器)可能不同呢?

对这个问题有什么见解吗?

更新/回答

一些建议是使用jcmd(https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html),因为网站告诉“本机内存跟踪”。但是,如果您仔细阅读该页面,您将看到

由于 NMT 不跟踪非 JVM 代码的内存分配,因此您可能必须使用操作系统支持的工具来检测本机代码中的内存泄漏。

因此,如果本机库内部泄漏,jcmd不是一个选项。

在对互联网进行数天的爬网并尝试各种分析器之后,解决此问题最有效的方法是使用jemalloc分析器。

这个页面帮助了我很多!https://gdstechnology.blog.gov.uk/2015/12/11/using-jemalloc-to-get-to-the-bottom-of-a-memory-leak/


答案 1

top和其他操作系统级别的工具显示 JVM 进程消耗了多少系统内存。由命令行选项定义的 Java 堆只是该内存的一部分。除了堆 JVM 本身还需要一些内存。然后是Java线程,每个线程都需要一定量的内存。和元空间/永久生成。还有其他几个。您可以阅读此博客文章此SO答案以获取更多信息。-Xmx

关于转储文件的大小和实际的堆大小,@arnab-biswas的答案肯定是正确的。MAT 报告实际使用的堆的大小,由活动对象使用。但堆转储包含整个堆,包括垃圾。


答案 2

我也经历过类似的情况。差异(HPROF 文件大小 - MAT 指示的堆大小)实际上是垃圾(无法访问的对象)。MAT 中无法访问的对象直方图在这里应该会有所帮助。

jmap -F -dump:live,format=b,file=<file_name.hprof> <process_id>只会转储活动对象,而不是垃圾。


推荐