跳到主要内容

JEP 143:改进竞争锁定

QWen Max 中英对照

概述

提升有争用的 Java 对象监视器的性能。

目标

改善以下基准和测试所衡量的有争用 Java 对象监视器的整体性能:

  • CallTimerGrid(虽然更多是压力测试而不是基准测试)
  • Dacapo-bach(曾为 dacapo2009)
  • _ avrora
  • _ batik
  • _ fop
  • _ h2
  • _ luindex
  • _ lusearch
  • _ pmd
  • _ sunflow
  • _ tomcat
  • _ tradebeans
  • _ tradesoap
  • _ xalan
  • DerbyContentionModelCounted
  • HighContentionSimulator
  • LockLoops-JSR166-Doug-Sept2009(曾为 LockLoops)
  • PointBase
  • SPECjbb2013-critical(曾为 specjbb2005)
  • SPECjbb2013-max
  • specjvm2008
  • volano29(曾为 volano2509)

非目标

该项目的目标并非解决内部 VM 监视器或互斥锁的任何性能改进问题;Java 监视器和内部 VM 监视器/互斥锁由不同的代码实现。虽然此项目中的某些概念可能适用于内部 VM 监视器/互斥锁,但代码并不直接适用。

此项目的目标并非是在每个基准测试或测试中都提高有争用的 Java 监视器性能;在某些情况下,某个特定的基准测试或测试可能会出现性能下降。为了在另一个基准测试或测试中获得性能提升,这种性能下降可能被认为是可接受的。

成功指标

如果通过上述基准测试能够证明性能有所提升,并且没有显著的性能下降相抵消,那么该项目将被视为成功。

对于无竞争锁,不得出现非微不足道的性能退化。

动机

改进有争用的锁将显著使实际应用受益,此外还有 Volano 和 DaCapo 等行业基准测试。

描述

该项目将探讨以下与有争用的 Java 监视器相关的性能改进领域:

  • 字段重排序与缓存行对齐
  • 加速 PlatformEvent::unpark() 操作
  • 加速 Java 监视器进入操作
  • 加速 Java 监视器退出操作
  • 加速 Java 监视器的 notify / notifyAll 操作

原始的工作主体还包括“更快的哈希码”的变更;由于 Java 对象哈希码支持与有争用的 Java 监视器并无直接关系,因此该工作将不包含在此项目中。

该项目还将为在工作过程中发现的各种错误生成修复程序;这些错误修复将独立于性能改进工作进行管理,以便修复程序可以更早地集成。

出于管理上的简便,该项目被以下“伞形”漏洞所涵盖:

JDK-6607129 在争用锁自旋循环中减少 L2$ 一致性缺失流量,特别是针对 ctn 系列上的 derby 数据库。

然而,随着子任务或错误修复的完成,这些工作将使用单独的错误编号(bug id)进行集成。这使得整个项目可以通过一个错误编号(JDK-6607129)来引用,同时允许增量改进比等待整个项目完成更快地可用。

测试

功能测试

似乎并没有专门针对 Java 监视器的功能测试集,而且也没有必要存在这样一个测试集。Java 监视器即使在最简单的 Java 程序中也被广泛使用,因此 Java 监视器几乎任何功能上的故障都应该显而易见。

压力测试

需要有一组众所周知的 Java 监视器压力测试。这些测试可以是针对特定 Java 监视器场景的目标压力测试,也可以是广为人知的、通常作为 Java 监视器重度使用者的测试,并通过特定的压力诱导选项来运行。

注意:使用 -XX:-UseBiasedLocking -XX:+UseHeavyMonitors 可绕过偏向锁和基于栈的锁;强制使用 ObjectMonitor 对象。

字段重排和缓存行对齐子任务压力测试

压力测试应侧重于生成大量活动的 ObjectMonitor 对象。压力测试的目标是峰值 ObjectMonitor 使用率、ObjectMonitor 块分配算法以及 ObjectMonitor 空闲列表管理代码。以下是具体目标:

  1. 对于小型到中型配置,具有相同或更好的峰值 ObjectMonitor 使用率,
  2. 不存在内存泄漏,并且
  3. 不存在数据结构管理故障。

加速 PlatformEvent::unpark() 子任务压力测试

压力测试应侧重于大量的并发等待线程和/或并发进入-退出线程。进入-等待-退出线程与进入-退出线程的混合比例应可配置。压力测试的目标是后继机制。

目标:不因丢失的 unpark 操作而导致挂起。

快速 Java 监视器进入操作子任务压力测试

压力测试应侧重于在可扩展的并行线程数量下,进入和退出操作的正确性。压力测试的目标是 Java 监视器所有权。

目标:没有所有权冲突,即不存在多个线程都认为自己拥有 Java 监视器的情况。

快速 Java 监视器退出操作子任务压力测试

应该通过“加速 PlatformEvent::unpark()”和“快速 Java 监视器进入操作”子任务的压力测试来覆盖。

快速 Java 监视器 Notify/NotifyAll 操作子任务压力测试

压力测试应侧重于在可扩展的并行线程数量下,enter-wait-exit 操作的正确性。压力测试的目标是在 wait() 完成后重新进入 Java 监视器时,检查其所有权的正确性。

目标:没有任何所有权冲突,即不存在多个线程都认为自己拥有 Java 监视器的情况。