伪共享和缓存行填充,Java并发编程还能这么优化!

  • 时间:
  • 浏览:0

关于伪共享的文章导致 着太多了,对于应用程序池池编程来说,不为啥是应用程序池池出理 列表和数组的后后,要非常注意伪共享的问提图片。而且不仅无法发挥应用程序池池的优势,还导致 着比单应用程序池性能还差。随着JAVA版本的更新,再各个版本上减少伪共享的做法删剪都是区别,一不小心代码导致 着就失效了,要注意进行测试。这篇文章总结一下。

原文发布时间为:2018-07-12

本文作者:Binhua

本文来自云栖社区战略相互合作伙伴“Java架构沉思录”,了解相关信息可可不都可以 关注“Java架构沉思录”。

参考

为了让可伸缩性与应用程序池数呈线性关系,就可不都可以确保不需要有另另四个 应用程序池往同另另四个 变量或缓存行中写。另另四个 应用程序池写同另另四个 变量可可不都可以 在代码中发现。为了挑选互相独立的变量否是共享了同另另四个 缓存行,就可不都可以可不都可以 解内存布局,或找个工具真不知道们。Intel VTune太多另另另四个 另另四个 分析工具。本文中我将解释Java对象的内存布局以及亲戚亲戚朋友该如何填充缓存行以出理 伪共享。

执行时,可不都可以打上去虚拟机参数-XX:-RestrictContended,@Contended注释才会生效。太多文章把这种漏掉了,那样的话实际上就可不都可以可不都可以 起作用。

(后记:以上代码基于32位JDK测试,64位JDK下,对象头大小不同,有空再测试一下)

JAVA 7下的方案

上端这种例子在JAVA 7下导致 着不适用了。导致 着JAVA 7会优化掉无用的字段,可可不都可以 参考:http://ifeve.com/false-shareing-java-7-cn/。

有哪些是伪共享

关于伪共享讲解最清楚的是这篇文章:http://developer.51cto.com/art/20160 6/398232.htm,我这里就直接摘抄其对伪共享的解释:

缓存系统中是以缓存行(cache line)为单位存储的。缓存行是2的整数幂个连续字节,一般为32-256个字节。最常见的缓存行大小是6另另四个 字节。当应用程序池池修改互相独立的变量时,导致 着有有哪些变量共享同另另四个 缓存行,就会无意中影响彼此的性能,这太多伪共享。缓存行上的写竞争是运行在SMP系统中并行应用程序池实现可伸缩性最重要的限制因素。他们将伪共享描述成无声的性能杀手,导致 着从代码中先要看清楚否是会跳出伪共享。

JAVA 8下的方案

在JAVA 8中,缓存行填充终于被JAVA原生支持了。JAVA 8中打上去了另另四个 @Contended的注解,打上去这种的注解,导致 着在自动进行缓存行填充。以上的例子可可不都可以 改为:

图1说明了伪共享的问提图片。在核心1上运行的应用程序池想更新变量X,同去核心2上的应用程序池我应该 更新变量Y。不幸的是,这另四个多 变量在同另另四个 缓存行中。每个应用程序池删剪都是去竞争缓存行的所有权来更新变量。导致 着核心1获得了所有权,缓存子系统导致 着使核心2中对应的缓存行失效。当核心2获得了所有权而且执行更新操作,核心1就要使此人 对应的缓存行失效。这会来来回回的经过L3缓存,大大影响了性能。导致 着互相竞争的核心居于不同的插槽,就要额外横跨插槽连接,问提图片导致 着更加严重。

而且,JAVA 7下做缓存行填充更麻烦了,可不都可以使用继承的方法来出理 填充被优化掉,这篇文章http://ifeve.com/false-shareing-java-7-cn/里的例子我确实删剪都是很好,于是我此人 做了这种优化,使其更通用:

JAVA 6下的方案

http://mechanical-sympathy.blogspot.hk/2011/08/false-sharing-java-7.html

http://mechanical-sympathy.blogspot.com/2011/07/false-sharing.html

VolatileLong通过填充这种无用的字段p1,p2,p3,p4,p5,p6,再考虑到对象头也占用8bit, 刚好把对象占用的内存扩展到刚好占64bytes(导致 着64bytes的整数倍)。另另另四个 就出理 了另另四个 缓存行中加载多个对象。但这种方法现在可不都可以可不都可以 适应JAVA6 及后后的版本了。

出理 伪共享的方法是使用缓存行填充,使另另四个 对象占用的内存大小刚好为64bytes或它的整数倍,另另另四个 就保证了另另四个 缓存行里不需要有多个对象。这篇文章http://developer.51cto.com/art/20160 6/398232.htm提供了缓存行填充的例子:

@Contended注释还可可不都可以 打上去在字段上,今后再写文章删剪介绍它的用法。



前言

http://robsjava.blogspot.com/2014/03/what-is-false-sharing.html

(注:导致 着亲戚亲戚朋友的填充使对象size大于64bytes,比如多填充16bytes– public long p1, p2, p3, p4, p5, p6, p7, p8;。理论上同样应该出理 伪共享问提图片,但事实是另另另四个 的话执行速率单位同样慢几倍,只比可不都可以可不都可以 使用填充好这种而已。还可不都可以可不都可以 理解其导致 着。太多测试下来,可不都可以是64bytes的整数倍)

把padding插进基类上端,可可不都可以 出理 优化。(这好像可不都可以可不都可以 有哪些道理好讲的,JAVA7的内存优化算法问提图片,能绕则绕)。不过,这种方法为啥看删剪都是点烦,借用另外另另四个 博主的话:做个java应用程序池池员先要。