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

Java堆转储和堆分析后的堆大小不同,java,eclipse,memory-leaks,jvm,heap-dump,Java,Eclipse,Memory Leaks,Jvm,Heap Dump,我遇到内存泄漏,下面是一些细节 发生泄漏后 顶部显示50GB内存作为住宅 堆转储文件大小为25GB EclipseMat analyzer告诉我堆大小是10GB 在发生泄漏之前 顶部显示30GB内存作为住宅 堆转储文件大小为20GB EclipseMat analyzer告诉我堆大小是10GB 我非常惊讶top、堆转储大小和实际堆大小之间的差异。 我猜top和heap之间的区别在于垃圾收集器堆和本机堆区域的可能性。 但是,堆转储文件大小和实际堆大小(来自EclipseMat analyz

我遇到内存泄漏,下面是一些细节

发生泄漏后

  • 顶部显示50GB内存作为住宅
  • 堆转储文件大小为25GB
  • EclipseMat analyzer告诉我堆大小是10GB
在发生泄漏之前

  • 顶部显示30GB内存作为住宅
  • 堆转储文件大小为20GB
  • EclipseMat analyzer告诉我堆大小是10GB
我非常惊讶top、堆转储大小和实际堆大小之间的差异。 我猜top和heap之间的区别在于垃圾收集器堆和本机堆区域的可能性。 但是,堆转储文件大小和实际堆大小(来自EclipseMat analyzer)为什么会不同呢

对这个问题有什么见解吗

更新/回答

一些建议是使用jcmd(),因为该网站告诉我们“本机内存跟踪”。但是,如果你仔细阅读这一页,你会发现

因为NMT不跟踪非JVM代码的内存分配,所以您可以 必须使用操作系统支持的工具来检测内存 本机代码中存在漏洞

因此,在本机库内部发生泄漏的情况下,jcmd不是一个选项

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

这一页对我帮助很大!
我也经历过类似的情况。区别(HPROF文件大小—MAT指示的堆大小)实际上是垃圾(无法访问的对象)。MAT中的不可访问对象直方图在这里应该有所帮助


jmap-F-dump:live,format=b,file=
只转储live对象,而不转储垃圾。

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


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

为了监视本机内存,您需要使用
-XX:NativeMemoryTracking=summary
-XX:NativeMemoryTracking=detail
启动应用程序。请注意,存在性能损失,因此在生产中进行此操作之前请三思

当内存跟踪处于活动状态时,您可以使用
jcmd VM.native\u内存摘要
。还有其他可用的命令,请检查或搜索本机内存跟踪


编辑:在回答之前,我没有按照链接进行操作,您可能正在寻找类似的内容。

堆转储: 堆转储是Java进程在某个时间点的内存快照。持久化此数据有不同的格式,根据格式的不同,它可能包含不同的信息,但通常快照包含有关触发快照时堆中java对象和类的信息。通常,在写入堆转储之前会触发完整GC,因此它包含关于剩余对象的信息


有关MAT的信息,请访问可靠/官方来源。让我试一试

1) 为什么我的JVM进程(顶部显示)消耗的内存大于堆 尺寸

因为JVM进程的总内存消耗不仅仅包括Java堆。举几个例子:

  • 生成(JIT:ed)代码
  • 加载的库(包括jar和类文件)
  • java堆的控制结构
  • 线程堆栈
  • 用户本机内存(JNI中的malloc:ed)
可信/官方来源:和

2) 为什么堆转储大小比MAT报告的大得多

因为MAT不显示完整的堆。在索引创建期间,内存分析器会删除无法访问的对象,因为各种垃圾收集器算法往往会留下一些垃圾


可靠/官方消息来源:

谢谢,我现在明白了。但我仍然需要知道住宅规模和堆规模之间的区别。请参阅其他有趣的链接,谢谢您的回答。看起来您建议使用NativeMemoryTracking,但这并不能真正跟踪本机库本身的内存分配。它只能根据此跟踪java代码分配。“由于NMT不跟踪非JVM代码的内存分配,您可能必须使用操作系统支持的工具来检测本机代码中的内存泄漏。”