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

问题描述:

我已经写了一个java应用程序,并且我已经在Fedora 24下运行了java进程。然后我检查了jconsole并发现它使用了大约5到10兆字节的内存。 垃圾收集的效果也可以在图中看到。这个java进程为什么不释放内存?

下面是截图: jconsole screenshot

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

下面是截图:

System Monitor screenshot

请告诉我,为什么不释放过程中未使用的内存?

有什么办法可以释放它吗?

+1

什么是这个Java应用程序?摇摆? –

+0

@CoderinoJavarino no。这些名字可以在他们的标题和我的文字中看到。 –

+0

你为什么在意?这是intellij,一个非常大的基于Java的程序。至少在所示的两个流程中,您并不是抱怨Chrome在超过100MB的情况下。 100MB并不是真正的内存 - 你的Gnome进程将需要更多。如果您真的有问题,请告诉我们。 100MB的内存已经不再是了。 – stdunbar

是有区别的使用堆和分配堆之间后持有的所有多余的堆上。图中的蓝线是已使用的堆 - 堆中有多少实际上是存放对象的。没有显示的是分配的堆的大小 - 这是更大的,通常要大得多,以便JVM可以分配更多的对象,而不会耗尽空间并且不得不返回到操作系统以获得更多内存(这是昂贵的)。在你的情况下,系统显示的100MB中有一些是JVM本身,但其中大部分可能是已分配但未使用的堆。

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

系统监视器中报告的内存是进程使用的所有内存,而不仅仅是Java堆。该存储器包括:虚拟机本身的

  • 可执行文件和库已经加载
  • 工作空间,为VM 作为一个过程在这样的事情作为热点编译器,GC,IO缓冲区,屏幕和图形缓存,读取VM文件等
  • Java堆和其他报告的内存结构

在你的情况下,过程的10MB被用于存储Java堆栈和Java对象。另外90MB是Java程序本身和VM内部的内存。

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

为了提高性能,您通常应该允许JVM保留从GC中释放的大量堆。为什么?因为我们知道JVM将立即需要重新开始分配内存,并且对于Java的进程(以及操作系统)来说更有效率来保持这一点。

因此,简言之:

  • 系统监视器显示了整个JVM进程
  • Java堆使用的内存仅在过程
  • 它是使用内存的项目之一(一般情况下)JVM在GC之后可以保存(至少部分)堆,因为我们几乎肯定会在接下来的几秒钟内使用它
  • 这种情况下的Java堆在正常范围,以及默认的内存配置案允许Java到GC