为什么我的Java堆转储大小比使用的内存小得多?

The*_*ter 11 java memory-leaks heap-memory jmap heap-dump

问题

我们正试图在我们的Web应用程序中找到大内存泄漏的罪魁祸首.我们在查找内存泄漏方面经验非常有限,但我们发现如何jmap在Eclipse MAT中使用和分析它来进行Java堆转储.

但是,我们的应用程序使用56/60GB内存,堆转储的大小只有16GB,在Eclipse MAT中甚至更少.

上下文

我们的服务器在Ubuntu 14.04上使用Wildfly 8.2.0作为我们的Java应用程序,其进程使用95%的可用内存.进行转储时,我们的缓冲区/缓存已用空间为56GB.

我们使用以下命令创建转储: sudo -u {application user} jmap -dump:file=/mnt/heapdump/dump_prd.bin {pid}

堆转储文件大小为16,4GB,当使用Eclipse MAT进行分析时,它表示有大约1GB的活动对象和大约14,8GB的无法访问/浅堆.

编辑:这里有一些关于我们看到的问题的更多信息.我们监视内存使用情况,我们看到它的增长和增长,直到剩下大约300mb的可用内存.然后它保持在那个内存量附近,直到进程崩溃,不幸的是在应用程序日志中没有错误.

这使我们假设它是一个硬OOM错误,因为这只发生在内存接近耗尽时.我们使用-Xms25000m -Xmx40000mJVM 的设置.

基本上,我们想知道为什么我们的大部分内存都没有在这个转储中被捕获.顶部保留的大小类看起来并不太可疑,所以我们想知道是否存在与堆转储有关的问题我们做错了什么.

Bra*_*don 16

转储堆时,JVM将首先运行垃圾收集周期以释放任何无法访问的对象.

如何在没有垃圾收集的情况下在Java 5上进行堆转储?

根据我的经验,在一个真正的OutOfMemoryError中,你的应用程序只需要比可用的更多的堆空间,这个GC是一个傻瓜的差事,最后的堆转储将是最大的.堆大小.

当堆转储小得多时,这意味着系统不是真正的内存不足,但可能有内存压力.例如,存在java.lang.OutOfMemoryError: GC overhead limit exceeded错误,这意味着JVM可能已经能够释放足够的内存来为一些新的分配请求提供服务,但它必须花费太多时间来收集垃圾.

您也可能没有内存问题.是什么让你觉得你这样做?您没有提到任何有关堆使用或OutOfMemoryError的内容.您刚才提到了JVM在操作系统上的内存占用.

  • 不幸的是,这并不完全正确。仅当转储操作与“live”子选项一起使用时才会发生这种情况:[`jmap -dump:live,file=...`](https://docs.oracle.com/javase/8/docs/ technotes/tools/unix/jmap.html),在这种情况下,将有一个完整的 GC 以便仅转储活动对象。确切地说,这并没有发生,命令和垫子都指示无法访问的对象已将其放入转储中。有几个原因可以解释为什么在转储、宽指针之前的某个时候会发生完整的 GC。 (2认同)

jco*_*oll 7

根据我的经验,堆转储远小于实际使用的内存可能是由于 JNI 中的泄漏造成的。

尽管您不直接使用任何本机代码,但仍有某些库使用它来加速。

在我们的例子中,这是一个放气装置充气装置没有正确结束。