跳到主要内容

JEP 351:ZGC:取消提交未使用的内存(实验性)

概括

增强 ZGC 以将未使用的堆内存返回给操作系统。

动机

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

  • 资源按使用付费的容器环境。

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

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

HotSpot 中的其他垃圾收集器(例如 G1 和 Shenandoah)现在提供了此功能,某些类别的用户发现该功能非常有用。将此功能添加到 ZGC 将会受到同一组用户的欢迎。

描述

ZGC 堆由一组称为_ZPage_的堆区域组成。每个 ZPage 都与可变数量的已提交堆内存相关联。当 ZGC 压缩堆时,ZPage 被释放并插入到页面缓存 ZPageCache_中_。页面缓存中的 ZPage 已准备好重新使用以满足新的堆分配,在这种情况下,它们将从缓存中删除。页面缓存对于性能至关重要,因为提交和取消提交内存是昂贵的操作。

页面缓存中的 ZPage 集表示堆中未使用的部分,这些部分_可以_未提交并返回到操作系统。因此,可以通过简单地从页面缓存中逐出一组精心选择的 ZPage,并取消提交与这些页面关联的内存来完成取消提交内存。页面缓存已经按照最近最少使用 (LRU) 的顺序保存 ZPage,并按大小(小、中、大)分隔,因此逐出 ZPage 和取消提交内存的机制相对简单。挑战在于设计决定何时从缓存中逐出 ZPage 的策略。

一个简单的策略是设置一个超时或延迟值,指定 ZPage 在被逐出之前可以在页面缓存中保留多长时间。该超时将有一些合理的默认值,可以使用命令行选项来覆盖它。 Shenandoah GC 使用这样的策略,默认值为 5 分钟,并且命令行选项-XX:ShenandoahUncommitDelay=<milliseconds>可以覆盖默认值。

像上面这样的政策可能会运作得相当好。然而,人们还可以设想更复杂的策略,不涉及添加新的命令行选项。例如,根据 GC 频率或一些其他数据找到合适的超时值的启发式方法。我们将首先提供一个简单的超时策略(带有一个-XX:ZUncommitDelay=<seconds>选项),并在稍后提供更复杂的策略(如果找到)。

默认情况下将启用取消提交功能。但无论策略如何决定,ZGC 都不应取消内存提交,从而使堆低于其最小大小 ( -Xms)。这意味着如果 JVM 以-Xms等于最大堆大小 ( ) 的最小堆大小 ( -Xmx) 启动,则取消提交功能将被有效禁用。-XX:-ZUncommit还将提供显式禁用此功能的选项。

最后,Linux/x64 上的 ZGC 使用 tmpfs 或 Hugetlbfs 文件来支持堆。取消提交这些文件使用的内存需要fallocate(2)支持FALLOC_FL_PUNCH_HOLE,该支持首次出现在 Linux 3.5 (tmpfs) 和 4.3 (hugetlbfs) 中。在较旧的 Linux 内核上运行时,ZGC 应继续像以前一样工作,但取消提交功能被禁用。

测试

  • 将开发一个或多个验证未提交功能的 jtreg 测试。

  • 现有基准(例如 SPECjbb 和 SPECjvm)将用于验证在使用默认策略时我们没有看到可测量的延迟或吞吐量回归。