有没有办法降低Java堆不使用时?
目前我正在研究一个Java应用程序,并努力优化其内存使用。 据我所知,我遵循正确垃圾收集的指导方针。 然而,似乎我的堆似乎坐在最大的大小,即使它不需要。
当计算机没有被某人使用时,我的程序每小时运行一次资源密集型任务。 这个任务使用了一大块内存,但是在任务完成后立即释放。 NetBeans分析器显示内存使用情况如下所示:
我真的希望在不使用的时候把所有的堆空间放回操作系统。 我没有任何理由要这么做,而这个计划甚至不会在一个小时内做任何事情。
这可能吗? 谢谢。
你也许可以玩-XX:MaxHeapFreeRatio
– 这是GC缩小之前自由堆的最大百分比(默认70)。 也许设置它稍低(40或50?),然后使用System.gc()
可能会System.gc()
一些时间来获得所需的行为?
但是,没有办法强制这个事情发生,但是你可以试着鼓励JVM这样做,但是你不能只是随心所欲地将内存移走。 虽然上面的内容可能会缩小堆,但内存不一定会直接回传给操作系统(虽然在最近的JVM实现中)。
短版:是的,你可以。
长版本:
Java / JVM如何pipe理内存
对于大多数应用程序来说,JVM默认值是可以的。 看起来JVM希望应用程序只运行一段有限的时间。 因此,它似乎并没有自行释放内存。
为了帮助JVM确定如何以及何时执行垃圾回收,应该提供以下参数:
-
-Xms
指定最小的堆大小 -
–Xmx
指定最大的堆大小
对于服务器应用程序,添加: -server
这对我来说还不够 我想要更多的控制!
如果上述参数不够,可以影响JVM在垃圾收集方面的行为。
首先,您可以使用System.gc()
告诉虚拟机何时您认为垃圾收集有意义。 其次,您可以指定JVM应该使用哪个垃圾收集器:
不同种类的垃圾收集器:
-
串行GC
命令行参数:
-XX:+UseSerialGC
停止您的应用程序并执行GC。
-
并行GC
命令行参数:
-XX:+UseParallelGC -XX:ParallelGCThreads=value
与您的应用程序并行运行次要集合 。 减less主要集合所需的时间,但使用另一个线程。
-
平行压实GC
命令行参数:
-XX:+UseParallelOldGC
与您的应用程序并行运行主要的集合 。 使用更多的CPU资源,减less内存使用量。
-
CMS GC
命令行参数:
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=value -XX:+UseCMSInitiatingOccupancyOnly
执行较小的集合,比串行GC更频繁,从而限制应用程序的中断/停止。
-
G1
命令行参数:
-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC
实验(至less在Java 1.6中):试图确保应用程序永远不会停止超过1秒。
例
没有任何优化的Play Framework Web应用程序的内存使用情况: 正如你所看到的,它使用了相当多的堆空间,并且使用空间经常被释放。
在这种情况下,只有参数的优化是无效的。 有一些计划任务使用了相当多的内存。 在这种情况下,在内存密集型操作之后,通过使用CMS GC
与System.gc()
实现最佳性能。 因此,WebApp的内存使用量从1.8 GB降低到了400-500 MB。
您可以在这里看到VisualVM的另一个屏幕截图,它显示了JVM释放内存以及实际返回到操作系统的方式:
注意:我使用VisualVM的“执行GC”button在我的代码中执行GC而不是System.gc()
,因为消耗内存的计划任务仅在特定时间启动,并且使用VisualVM难以捕获。
进一步阅读
- 有关调整JVM GC的文章
- Oracle可用GC的文档
一种可能是让您的后台Java应用程序每小时启动一个外部jvm实例来运行您的任务。 这样,只有原始的jvm应用程序在任务之间运行。
Java最好保守秘密:-Xincgc它确实影响性能,但并不总是那么重要。 有时候,取决于你在做什么。 增量垃圾收集器把内存回传给系统相当好!
JVM不能这样工作。 你不能把它交还给操作系统。
正如四年前写过的一些人所指出的那样,如果您将正确的GC设置提供给JVM,则可以将内存返回给操作系统。
如果您的应用程序在闲置期间处于静止状态,则操作系统可能会为您replace这些页面,从而减轻对物理内存的压力。
http://www.linuxvox.com/2009/10/what-is-the-linux-kernel-parameter-vm-swappiness/