我正在研究Java应用程序,并努力优化其内存使用情况。据我所知,我正在遵循适当的垃圾收集指南。但是,似乎我的堆似乎处于最大大小,即使它不需要。
我的程序每小时运行一次资源密集型任务,此时计算机未被人使用。此任务使用了相当大的内存块,但在任务完成后立即释放所有内存。 NetBeans探查器显示内存使用情况如下所示:
我真的很想在不使用时将所有堆空间都交还给操作系统。没有理由让我把它全部占用,而程序甚至不会在至少一个小时内做任何事情。
这可能吗?感谢。
答案 0 :(得分:34)
您可以使用-XX:MaxHeapFreeRatio
- 这是在GC缩小之前可用的堆的最大百分比(默认为70)。也许将它设置得稍低(40或50?)然后使用System.gc()
可能需要一些时间才能达到理想的行为?
没有办法强迫这种情况发生,但是你可以尝试并鼓励JVM这样做,但你不能只是随心所欲地抽出记忆。虽然上面的内容可能会缩小堆,但内存不一定会直接返回给操作系统(尽管在最近的JVM实现中它也是如此。)
答案 1 :(得分:13)
简短版:是的,你可以。
长版:
对于大多数应用程序,JVM默认值都可以。看起来JVM希望应用程序只在有限的时间内运行。因此它似乎没有释放它自己的记忆。
为了帮助JVM决定如何以及何时执行垃圾收集,应提供以下参数:
-Xms
指定最小堆大小–Xmx
指定最大堆大小对于服务器应用程序,请添加:-server
如果上述参数不够,可以影响JVM关于垃圾收集的行为。
首先,当您认为垃圾收集有意义时,可以使用System.gc()
告诉VM。第二,您可以指定JVM应使用哪些垃圾收集器:
串行GC
命令行参数:-XX:+UseSerialGC
停止您的应用程序并执行GC。
并行GC
命令行参数:-XX:+UseParallelGC -XX:ParallelGCThreads=value
与您的应用程序并行运行次要集合。减少主要馆藏所需的时间,但使用另一个帖子。
并行压缩GC
命令行参数:-XX:+UseParallelOldGC
与您的应用程序并行运行主要馆藏。使用更多的CPU资源,减少内存使用量。
CMS GC
命令行参数:-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=value -XX:+UseCMSInitiatingOccupancyOnly
执行较小的集合,并且比 Serial GC 更频繁,从而限制了应用程序的中断/停止。
<强> G1 强>
命令行参数:-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC
实验(至少在Java 1.6中):尝试确保应用程序永远不会停止超过1秒。
没有任何优化的Play Framework Web应用程序的内存使用情况: 如您所见,它使用了相当多的堆空间,并且定期释放已用空间。
在这种情况下,仅使用参数的优化无效。有一些计划的任务使用了相当多的内存。在这种情况下,通过在内存密集型操作之后使用CMS GC
与System.gc()
结合来实现最佳性能。因此,WebApp的内存使用量从1.8 GB减少到大约400-500 MB。
你可以在这里看到另一个来自VisualVM的截图,它显示了JVM如何释放内存并实际返回到操作系统:
注意:我使用VisualVM的“执行GC”按钮在我的代码中执行GC而不是System.gc()
,因为消耗内存的计划任务仅在特定时间启动,而使用VisualVM更难捕获
答案 2 :(得分:4)
JVM无法正常工作。你不能把它还给OS。
正如四年前写的几个人所指出的,如果你给JVM提供了正确的GC设置,你可以给内存回服。
答案 3 :(得分:3)
一种可能性是让您的后台java应用程序每小时启动一个外部jvm实例来运行您的任务。这样,只有原始的jvm应用程序在任务之间运行。
答案 4 :(得分:3)
如果您的应用在不活动期间处于静止状态,操作系统可能会为您换出这些页面,从而减轻他们对物理内存的压力。
http://www.linuxvox.com/2009/10/what-is-the-linux-kernel-parameter-vm-swappiness/
答案 5 :(得分:3)
Java最好保守秘密:-Xincgc 它确实会影响性能,但并不总是如此。有时它确实取决于你正在做什么。 增量垃圾收集器很好地将内存传回系统!
答案 6 :(得分:2)
Java 12 使用G1GC支持此功能。
JEP 346:立即从G1返回未使用的承诺内存。
增强G1垃圾收集器,使其在空闲时自动将Java堆内存返回到操作系统。