为什么要有cpu高速缓存&伪共享问题

/ 默认分类 / 0 条评论 / 1203浏览

为什么要有cpu高速缓存

CPU存取数据的速度非常的快,一秒钟能够存取、处理十亿条指令和数据(术语:CPU主频1G),而内存就慢很多,快的内存能够达到几十兆就不错了,可见两者的速度差异很大。 为了解决CPU速度和内存速度的速度差异问题,内存中被CPU访问最频繁的数据和指令被复制入CPU中的缓存,这样CPU就不需要缓慢地去内存中取数据,cpu缓存中就有,就可以避免因为 内存速度地缓慢拖累导致cpu效率降低。

cpu告诉缓存可能有很多级,整体也就类似下面地结构

缓存内部数据结构是以行作为单位地,所以我们常会说cpu缓存行锁地概念,下图就是cpu缓存行地结构:

缓存行是cpu和主内存进行数据交换,缓存数据地基本单位。

所以,当cpu需要访问某个数据时,会先查看cpu缓存中是否有该数据,如果有就直接使用,如果没有就会去主内存中寻找,然后将主内存中该数据所在地址处缓存行单位大小地内存数据缓存到cpu 缓存中,所以这里缓存到cpu缓存行地数据不一定是单个变量,因为cpu缓存以缓存行未单位获取写入数据,所以可能本次缓存地数据中还包括了其他数据,然而我们前面介绍了cpu缓存行锁,同一时刻 缓存行中地数据只会被一个线程访问,所以这就会造成性能降低。这个问题就是java内存模型中地伪共享问题。

java中解决伪共享的方法

为了进一步提升性能,我们可以对每次获取的单个变量进行空间大小填充,使用一些无效的数据来填充剩余的缓存行大小的空间,这样cpu在获取缓存行单位大小的数据时就直接获取到了单个需要的变量数据, 其他空间都是我们生命变量是填充的无用的数据,保证在使用缓存时这些空间的数据不会被使用到,这样就让单个cpu缓存行性能提升了,其实也算是一种浪费空间换取时间的方式。

java中可以使用对象对单个共享变量进行封装,然后申明一些无关的数据填充剩余空间大小;或者使用@Contended('组名)注解声明在变量或类上,保证同一组的数据会在一个缓存行中。