有没有办法在不使用时降低 Java 堆?

发布于 2024-10-17 00:49:09 字数 334 浏览 5 评论 0原文

我目前正在开发一个 Java 应用程序,并致力于优化其内存使用。据我所知,我正在遵循正确的垃圾收集指南。然而,我的堆似乎达到了最大大小,尽管不需要它。

当计算机无人使用时,我的程序每小时运行一次资源密集型任务。该任务使用了相当大的内存块,但在任务完成后立即释放了所有内存。 NetBeans 分析器显示内存使用情况如下所示:

Java 程序内存使用

我真的很想提供所有堆不使用时将空间返回给操作系统。当程序至少在接下来的一个小时内不会做任何事情时,我没有理由霸占这一切。

这可能吗?谢谢。

I'm working on a Java application at the moment and working to optimize its memory usage. I'm following the guidelines for proper garbage collection as far as I am aware. However, it seems that my heap seems to sit at its maximum size, even though it is not needed.

My program runs a resource intensive task once an hour, when the computer is not in use by a person. This task uses a decent chunk of memory, but then frees it all immediately after the task completes. The NetBeans profiler reveals that memory usage looks like this:

Java program memory usage

I'd really like to give all of that heap space back to the OS when not in use. There is no reason for me to hog it all while the program won't even be doing anything for at least another hour.

Is this possible? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

衣神在巴黎 2024-10-24 00:49:09

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

然而,没有办法强制这种情况发生,您可以尝试并鼓励 JVM 这样做,但您不能在您想要的时候就将内存拉走。虽然上面的方法可能会缩小堆,但内存不一定会直接返回给操作系统(尽管在最近的 JVM 实现中确实如此。)

You could perhaps play around with -XX:MaxHeapFreeRatio - this is the maximum percentage (default 70) of the heap that is free before the GC shrinks it. Perhaps setting it a bit lower (40 or 50?) and then using System.gc() might go some lengths to get you the desired behaviour?

There's no way to force this to happen however, you can try and encourage the JVM to do so but you can't just yank memory away as and when you want to. And while the above may shrink the heap, that memory won't necessarily be handed straight back to the OS (though in recent implementations of the JVM it does.)

ㄖ落Θ余辉 2024-10-24 00:49:09

简短版本:是的,可以。

长版本:

Java/JVM 如何管理内存

对于大多数应用程序,JVM 默认值都可以。看起来 JVM 期望应用程序仅运行有限的时间。因此它似乎不会自行释放内存。

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

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

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

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

如果上述参数不够,您可以影响 JVM 关于垃圾收集的行为。

首先,您可以使用 System.gc() 告诉虚拟机您何时认为垃圾回收有意义。其次,您可以指定 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

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

  • G1

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

    实验性(至少在 Java 1.6 中):尝试确保应用程序的停止时间不会超过 1 秒。
    #例子
    未经任何优化的 Play Framework Web 应用程序的内存使用情况:
    Play 框架没有优化的 WebApp
    正如您所看到的,它使用了相当多的堆空间,并且使用的空间会定期释放。

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

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

JVM 正在释放内存并返回给操作系统
注意:我在代码中使用 VisualVM 的“执行 GC”按钮来执行 GC,而不是 System.gc(),因为消耗内存的计划任务仅在特定时间启动并且用 VisualVM 捕获有点困难。

进一步阅读

Short version: Yes you can.

Long version:

How Java/JVM manages memory

For most applications the JVM defaults are okay. It looks like the JVM expects applications to run only a limited period of time. Therefore it does not seem to free memory on it's own.

In order to help the JVM to decide how and when to perform garbage collection, the following parameters should be supplied:

  • -Xms Specifies the minimal heap size
  • –Xmx Specifies the maximal heap size

For server applications add: -server

That's not enough for me. I want more control!

In case the above mentioned parameters are not enough, you can influence the behavior of the JVM regarding garbage collection.

First you can use System.gc() to tell the VM when you believe garbage collection would make sense. And second you can specify which of the garbage collectors the JVM should use:

Different Kinds of Garbage collectors:

  • Serial GC

    Command line parameter: -XX:+UseSerialGC

    Stops your application and performs GC.

  • Parallel GC

    Command line parameter: -XX:+UseParallelGC -XX:ParallelGCThreads=value

    Runs minor collections in parallel with your application. Reduces time needed for major collections, but uses another thread.

  • Parallel Compacting GC

    Command line parameter: -XX:+UseParallelOldGC

    Runs major collections in parallel with your application. Uses more CPU resources, reduces memory usage.

  • CMS GC

    Command line parameter: -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=value -XX:+UseCMSInitiatingOccupancyOnly

    Performs smaller collections, and more often than Serial GC, thus limiting the breaks/stops of the application.

  • G1

    Command line parameter: -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC

    Experimental (at least in Java 1.6): Tries to make sure the application is never stopped for more than 1s.
    #Example
    Memory usage of a Play Framework web application without any optimizations:
    Play Framework WebApp without optimizations
    As you can see, it uses quite a lot of heap space, and the used space is regularly freed.

In this case the optimizations with parameters only were not effective. There were some scheduled tasks which used rather a lot of memory. In this case the best performance was achieved by using the CMS GC combined with System.gc() after the memory intensive operations. As a result the memory usage of the WebApp was reduced from 1.8 GB to around 400-500 MB.

You can see here another screenshot from the VisualVM which shows how memory is freed by the JVM and actually returned to the OS:

Memory is being freed by the JVM and returned to the OS
Note: I used the "Perform GC"-button of the VisualVM to perform the GC rather than System.gc() in my code, as the scheduled tasks which consume the memory are only launched at specific times and somewhat harder to capture with VisualVM.

Further Reading

老娘不死你永远是小三 2024-10-24 00:49:09

Java 12 使用 G1GC 支持此功能。

JEP 346:立即从 G1 返回未使用的提交内存。

增强G1垃圾收集器,以在空闲时自动将Java堆内存返回给操作系统。

https://openjdk.java.net/jeps/346

Java 13 使用 zgc 支持此功能

JEP 351:ZGC:取消提交未使用的内存

ZGC 当前不会取消提交并将内存返回给操作系统,即使该内存已长时间未使用也是如此。此行为并非对于所有类型的应用程序和环境都是最佳的,尤其是那些关注内存占用的应用程序和环境。例如:
资源按使用付费的容器环境。

  • 应用程序可能长时间空闲并与许多其他应用程序共享或竞争资源的环境。

  • 应用程序在执行期间可能有非常不同的堆空间要求。例如,启动期间所需的堆可能大于稳定状态执行期间所需的堆。

http://openjdk.java.net/jeps/351

Java 12 supports this feature using G1GC.

JEP 346: Promptly Return Unused Committed Memory from G1.

Enhance the G1 garbage collector to automatically return Java heap memory to the operating system when idle.

https://openjdk.java.net/jeps/346

Java 13 supports this feature using zgc

JEP 351: ZGC: Uncommit Unused Memory

ZGC does not currently uncommit and return memory to the operating system, even when that memory has been unused for a long time. This behavior is not optimal for all types of applications and environments, especially those where memory footprint is a concern. For example:
Container environments where resources are paid by use.

  • Environments where an application might be idle for long periods of time and is sharing or competing for resources with many other applications.

  • An application might have very different heap space requirements during its execution. For example, the heap needed during start up might be greater than what is needed later during steady state execution.

http://openjdk.java.net/jeps/351

别忘他 2024-10-24 00:49:09

一种可能性是让您的后台 java 应用程序每小时启动一个外部 jvm 实例来运行您的任务。这样,任务之间就只有原始的 jvm 应用程序在运行。

One possibility is to have your background java application launch an external jvm instance each hour to run your task. That way only your original jvm application is running between tasks.

浮云落日 2024-10-24 00:49:09

如果您的应用程序在不活动期间处于静止状态,操作系统可能会为您换出这些页面,从而减轻它们对物理内存的压力。

http://www.linuxvox。 com/2009/10/what-is-the-linux-kernel-parameter-vm-swappiness/

If your app is quiescent during periods of inactivity, it's possible the OS will swap out those pages for you, mitigating their pressure on physical memory.

http://www.linuxvox.com/2009/10/what-is-the-linux-kernel-parameter-vm-swappiness/

可可 2024-10-24 00:49:09

Java 最好的秘密:-Xincgc
它确实会影响性能,但并不总是那么大。有时确实如此,取决于您在做什么。
增量垃圾收集器很好地将内存交还给系统!

Java best kept secret: -Xincgc
It does impact performance but not always that much. Sometimes it does, depends on what you're doing.
The incremental garbage collector hands memory back to the system quite well !

九八野马 2024-10-24 00:49:09

JVM 不是这样工作的。您无法将其返还给操作系统。

正如自四年前撰写以来许多人所指出的那样,如果为 JVM 提供正确的 GC 设置,则可以将内存返还给操作系统。

The JVM doesn't work that way. You can't give it back to the OS.

As noted by several people since this was written four years ago, you can give memory back to the OS if you give the proper GC settings to the JVM.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文