Skip to content

JEP 142: Reduce Cache Contention on Specified Fields | 减少指定字段的缓存争用

摘要

定义一种方式来指定对象中的一个或多个字段可能在处理器核心之间产生高度竞争,以便虚拟机可以安排它们不与其他可能独立访问的字段或其他对象共享缓存行。

描述

当两个由不同核心使用的内存位置最终位于同一缓存行上,且至少有一个核心正在进行写入时,就会发生内存竞争。对于高度竞争的内存位置,这可能会成为严重的性能和可伸缩性问题。此增强的目的是避免核心之间的内存竞争,至少是在开发过程中我们可以轻松识别的字段上。

这个想法是在每个可能产生竞争的字段之前和之后添加填充,以确保没有其他字段(或其他对象)会落在同一缓存行上。在通常没有保证对象对齐的情况下,填充的大小需要与我们正在运行的机器的缓存行大小相同。如果可以保证特定的对象对齐,那么我们可以减少所需的填充量。例如,如果对象的第一个字段总是保证位于缓存行的开头,那么我们只需要在字段之前填充足够的空间以确保字段也位于缓存行的开头,然后在字段之后填充足够的空间以确保下一个字段位于后续缓存行的开头。

在类加载时,通过向类中添加足够的虚拟字段,可以相对容易地实现这种填充。之后更改类布局会更具挑战性,特别是在该类的实例已被分配和 / 或其某些方法已被即时编译之后。

如果我们想减少由于这种填充而浪费的内存,我们必须确保特定的对象对齐。然而,这是一个更为复杂的更改,除了类加载之外,它还将触及 JVM 的多个其他部分:分配代码(以确保特定对象的分配正确对齐,并标记这些对象以便将来保持对齐)、JIT 编译器(以了解哪些分配需要对齐,并发出正确的分配操作指令,或调用特殊的运行时方法)、垃圾收集器(以确保任何需要对齐的对象在移动时仍保持对齐)等。鉴于对齐可能只允许我们减少由于填充而浪费的内存占用,并且假设需要填充的大多数对象并不多,因此引入这种对齐要求可能会带来递减的回报。

主要挑战是如何允许开发人员指定哪些字段可能会产生竞争。一种通用的方法是使用注解(尽管这需要访问源代码)。这样,JVM 就可以以最佳方式处理指定的字段(即,仅通过填充它们,或者通过前面讨论的填充和对齐分配的组合)。

如果减少源代码不可用的对象(如标准库类的实例)上的缓存竞争很重要,那么可以为开发人员提供一个特殊的工厂方法,该方法将进行正确的对齐和填充,以便分配的对象不会与其他对象共享缓存行。

影响

  • 性能 / 可伸缩性:目标是提高多线程应用程序的性能,并使其具有更好的可伸缩性。但是,填充对象确实意味着更高的内存使用量。