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

时间:2015-08-28 13:02:59

标签: java memory-leaks heap-memory heap-dump jmap

问题

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

但是,我们的应用程序使用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错误,因为这只发生在内存接近耗尽时。我们为JVM使用-Xms25000m -Xmx40000m设置。

问题

基本上,我们想知道为什么我们的大部分内存都没有在此转储中捕获。顶级保留的大小类看起来不太可疑,所以我们想知道是否有与堆转储相关的东西我们做错了什么。

2 个答案:

答案 0 :(得分:15)

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

How can I take a heap dump on Java 5 without garbage collecting first?

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

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

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

答案 1 :(得分:1)

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

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

在我们的案例中,DeflaterInflater未正确结束。