为什么这个java进程不释放内存?

时间:2016-07-04 18:37:10

标签: java memory memory-management heap-memory

我编写了一个java应用程序,我在Fedora 24下运行了java进程。然后我检查了jconsole,发现它使用了大约5到10兆字节的内存。 垃圾收集的效果在图表中也可见。

以下是截图: jconsole screenshot

然后我检查了我的系统监视器,发现相同的进程ID有超过100兆字节的内存使用量。

以下是截图:

System Monitor screenshot

请告诉我为什么这个过程不会释放未使用的内存?

有没有办法释放它?

2 个答案:

答案 0 :(得分:3)

使用堆和已分配堆之间存在差异。图中的蓝线是用过的堆 - 实际持有对象的堆的数量。未显示的是分配的堆的大小 - 这个更大,通常要大得多,这样JVM可以分配更多的对象而不会耗尽空间并且必须返回操作系统以获得更多内存(这是昂贵的) )。在您的情况下,系统显示的100mb中的一些是JVM本身,但其中大部分可能已分配但未使用的堆。

当你运行Java程序而没有指定你希望它使用的堆大小时,JVM将尝试根据你的机器,操作系统,JVM版本等找出合理的设置。当我在我的网站上运行一个简单的Hello World时具有16GB RAM和Java 8的机器最初为堆分配了256mb。显然远远超过它的需要!如果我想强制它使用更少,我可以使用-Xms命令行设置初始堆分配,-Xmx设置允许的最大值。我的猜测是,如果你设置-Xms20m这样的东西,你会发现你的进程使用的内存更少。在IntelliJ中,将该设置添加到运行配置中的VM Options字段。

答案 1 :(得分:2)

系统监视器中报告的内存是进程使用的所有内存,而不仅仅是Java堆。此内存包括:

  • VM本身的可执行文件及其已加载的库
  • VM 的工作空间作为进程,用于Hotspot编译器,GC,IO缓冲区,屏幕和图形缓冲区,读取VM文件等
  • Java堆和其他可报告的内存结构

在您的情况下,正在使用10MB的进程来存储Java堆栈和Java对象。另外90MB是Java程序本身和VM内部的内存。

这是简短的答案,但还有另一个重要的考虑因素 - Java可以(并确实)将多余的堆释放回操作系统。这由-XX:MinHeapFreeRatio-XX:MaxHeapFreeRatio标志控制。默认情况下,MaxHeapFreeRatio是70% - 这几乎就是你的Heap图中显示的内容(锯齿图案从6MB到10MB以下)。如果您的应用程序具有明显更大的下降,您将在系统监视器中看到Java进程的(小)锯齿模式。

为了提高性能,通常应该允许JVM保留从GC中释放的大量堆。为什么?因为我们知道JVM将立即需要再次开始分配内存,并且Java的进程(和操作系统)更有效地保留它。

所以,总结一下:

  • 系统监视器显示整个JVM进程使用的内存
  • Java堆只是过程中使用内存的项目之一
  • (通常)JVM保持(至少某些)它在GC之后释放的堆的性能(通常)更高,因为我们几乎肯定会在接下来的几秒内使用它
  • 在这种情况下,Java堆在正常范围内振荡,在这种情况下,默认的内存配置允许Java在GC之后保留所有多余的堆