跳到主要内容

JEP 345:G1 的 NUMA 感知内存分配

概括

通过实施 NUMA 感知内存分配来提高大型计算机上的 G1 性能。

非目标

  • 实现除 G1 之外的 NUMA 支持收集器并不是目标。
  • 支持Linux以外的操作系统并不是我们的目标。
  • 让 G1 NUMA 感知的其他部分(例如任务队列窃取、记忆集或细化)并不是我们的目标。

动机

现代多插槽机器越来越多地具有非均匀内存访问(NUMA),即内存与每个插槽或核心的距离不相等。套接字之间的内存访问具有不同的性能特征,对更远的套接字的访问通常具有更多的延迟。

由 启用的并行收集器-XX:+UseParallelGC多年来一直支持 NUMA。这有助于提高跨多个套接字运行单个 JVM 的配置的性能。其他 HotSpot 收集器尚未享受此功能的好处,这意味着它们无法利用这种垂直多插槽 NUMA 扩展。大型企业应用程序尤其倾向于在多个套接字上使用大型堆配置运行,但他们希望在单个 JVM 中运行具有可管理性优势。使用 G1 收集器的用户越来越多地遇到这种扩展瓶颈。

描述

G1 的堆被组织为固定大小区域的集合。区域通常是一组物理页面,尽管在使用大页面(通过-XX:+UseLargePages)时,多个区域可能组成单个物理页面。

如果+XX:+UseNUMA指定了该选项,那么当 JVM 初始化时,区域将均匀分布在可用 NUMA 节点总数上。

在开始时固定每个区域的 NUMA 节点有点不灵活,但是可以通过以下增强来缓解这一点。为了为变异线程分配新对象,G1 可能需要分配新区域。它会优先从当前线程绑定的 NUMA 节点中选择一个空闲区域,以便该对象将保留在年轻代中的同一 NUMA 节点上。如果在为 mutator 分配区域期间同一 NUMA 节点上没有空闲区域,则 G1 将触发垃圾收集。要评估的另一种想法是从最近的 NUMA 节点开始,按距离顺序搜索其他 NUMA 节点的空闲区域。

我们不会尝试将对象保留在老一代的同一 NUMA 节点上。

巨大的地区被排除在这一分配政策之外。我们不会为这些地区做任何特别的事情。

测试

使用该选项的现有测试-XX:+UseNUMA应该可以消除任何正确性问题。我们假设使用 NUMA 硬件进行测试。

当 NUMA 感知分配关闭时,与原始代码应该没有性能差异。

风险和假设

我们假设大多数短命对象通常由分配它们的线程访问。对于大多数面向对象程序中的大多数短期对象来说确实如此。然而,有些程序这个假设并不完全成立,因此在某些情况下可能会出现性能下降。此外,好处还取决于底层系统的 NUMA 程度和此类系统上的 NUMA 节点之间迁移线程的频率之间的相互作用,尤其是在负载较高时。