JEP 143:改进竞争锁定
概述
提升有争用的 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
空闲列表管理代码。以下是具体目标:
- 对于小型到中型配置,具有相同或更好的峰值 ObjectMonitor 使用率,
- 不存在内存泄漏,并且
- 不存在数据结构管理故障。
加速 PlatformEvent::unpark()
子任务压力测试
压力测试应侧重于大量的并发等待线程和/或并发进入-退出线程。进入-等待-退出线程与进入-退出线程的混合比例应可配置。压力测试的目标是后继机制。
目标:不因丢失的 unpark 操作而导致挂起。
快速 Java 监视器进入操作子任务压力测试
压力测试应侧重于在可扩展的并行线程数量下,进入和退出操作的正确性。压力测试的目标是 Java 监视器所有权。
目标:没有所有权冲突,即不存在多个线程都认为自己拥有 Java 监视器的情况。
快速 Java 监视器退出操作子任务压力测试
应该通过“加速 PlatformEvent::unpark()
”和“快速 Java 监视器进入操作”子任务的压力测试来覆盖。
快速 Java 监视器 Notify/NotifyAll 操作子任务压力测试
压力测试应侧重于在可扩展的并行线程数量下,enter-wait-exit
操作的正确性。压力测试的目标是在 wait()
完成后重新进入 Java 监视器时,检查其所有权的正确性。
目标:没有任何所有权冲突,即不存在多个线程都认为自己拥有 Java 监视器的情况。