有没有办法在不使用时降低Java堆?Java/JVM 如何管理内存这对我来说还不够。我想要更多的控制!不同类型的垃圾收集器:例延伸阅读

2022-08-31 16:43:57

我目前正在开发一个Java应用程序,并努力优化其内存使用率。据我所知,我正在遵循正确垃圾回收的准则。但是,似乎我的堆似乎处于最大大小,即使不需要它。

我的程序每小时运行一次资源密集型任务,此时计算机未被人使用。此任务使用相当多的内存块,但在任务完成后立即将其全部释放。NetBeans 探查器显示内存使用情况如下所示:

Java program memory usage

我真的很想在不使用时将所有堆空间还给操作系统。我没有理由把所有东西都花光,而程序甚至至少再过一个小时也不会做任何事情。

这可能吗?谢谢。


答案 1

您也许可以尝试一下 - 这是在GC收缩之前可用堆的最大百分比(默认为70)。也许将其设置得更低一点(40或50?),然后使用可能会花费一些时间来获得所需的行为?-XX:MaxHeapFreeRatioSystem.gc()

但是,没有办法强制发生这种情况,您可以尝试并鼓励JVM这样做,但您不能随心所欲地将内存拉开。虽然上述内容可能会缩小堆,但该内存不一定会直接交还给操作系统(尽管在最近的JVM实现中确实如此)。


答案 2

简短版本:是的,您可以。

长版本:

Java/JVM 如何管理内存

对于大多数应用程序,JVM 缺省值是可以的。看起来 JVM 期望应用程序只在有限的时间段内运行。因此,它似乎没有自己释放内存。

为了帮助 JVM 决定如何以及何时执行垃圾回收,应提供以下参数:

  • -Xms指定最小堆大小
  • –Xmx指定最大堆大小

对于服务器应用程序,添加:-server

这对我来说还不够。我想要更多的控制!

如果上述参数不够,您可以影响JVM在垃圾回收方面的行为。

首先,你可以用它来告诉 VM 你何时认为垃圾回收是有意义的。其次,您可以指定 JVM 应使用哪些垃圾回收器:System.gc()

不同类型的垃圾收集器:

  • 串行气相色谱仪

    命令行参数:-XX:+UseSerialGC

    停止应用程序并执行 GC。

  • 并行气相色谱

    命令行参数:-XX:+UseParallelGC -XX:ParallelGCThreads=value

    与应用程序并行运行次要集合。减少主要集合所需的时间,但使用另一个线程。

  • 并行压缩 GC

    命令行参数:-XX:+UseParallelOldGC

    与应用程序并行运行主要集合。使用更多的CPU资源,减少内存使用。

  • 内容管理系统

    命令行参数:-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=value -XX:+UseCMSInitiatingOccupancyOnly

    执行较小的集合,并且比串行GC更频繁,从而限制了应用程序的中断/停止。

  • G1

    命令行参数:-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC

    实验性(至少在Java 1.6中):尝试确保应用程序永远不会停止超过1秒。

Play Framework Web应用程序的内存使用情况没有任何优化:Play Framework WebApp without optimizations如您所见,它使用了大量的堆空间,并且使用的空间会定期释放。

在这种情况下,仅使用参数的优化无效。有一些计划任务使用了大量的内存。在这种情况下,最佳性能是通过使用与内存密集型操作相结合来实现的。因此,WebApp的内存使用量从1.8 GB减少到大约400-500 MB。CMS GCSystem.gc()

您可以在这里看到来自VisualVM的另一个屏幕截图,它显示了JVM如何释放内存并实际返回到操作系统:

Memory is being freed by the JVM and returned to the OS注意:我使用 VisualVM 的“执行 GC”按钮来执行 GC 而不是在我的代码中,因为消耗内存的计划任务仅在特定时间启动,并且使用 VisualVM 捕获起来有点困难。System.gc()

延伸阅读


推荐