为什么Java8的@Contended注解采用两倍主流缓存行大小的128字节填充
相邻缓存行预取器的常见启用场景
- 绝大多数x86架构的桌面、服务器CPU默认开启相邻缓存行预取(也叫扇区预取),属于硬件层面默认生效的性能优化策略,无需上层软件主动配置触发
- 当CPU检测到程序正在连续访问线性内存地址时,会自动将当前正在访问的缓存行的相邻下一条缓存行同步加载到CPU缓存中,这个优化在数组顺序遍历等连续内存访问场景下,能降低30%以上的缓存未命中率,提升访问效率
- 部分ARM服务器级CPU的默认预取策略也会加载相邻的1~2条缓存行,这类场景下伪共享的影响范围会从单条64B缓存行扩大到128B甚至更大
@Contended 填充128字节的设计逻辑
- 该设计采用的是最坏场景兼容思路:如果只给被修饰字段/对象前后填充64字节,当目标数据刚好落在两条可被预取的缓存行边界时,还是可能和相邻的其他数据触发伪共享
- 前后各填充128字节相当于给目标数据划出了完全隔离的128B内存区间,哪怕硬件触发相邻缓存行预取,也不会将其他无关数据和目标数据加载到同一段预取缓存行范围内,从根本上避免预取机制导致的伪共享问题
- HotSpot虚拟机也提供了调整参数
-XX:ContendedPaddingWidth,如果你明确运行环境已经关闭了相邻缓存行预取,可以手动将填充宽度改为64B减少不必要的内存浪费
内容的提问来源于stack exchange,提问作者bin
相关产品推荐
相关产品推荐

