缓存伪共享问题以及解决方案缓存行填充
缓存伪共享
共享对象存在同一个缓存中,由于MESI协议,一个对象中一些不需要改变的属性因为其他改变的属性,导致整个对象的缓存进入到M被修改状态。
MESI缓存一致性协议:https://blog.csdn.net/huangyueranbbc/article/details/84554271
目前的CPU是通常按照32或者64字节的缓存行(Cache Line)进行读取,如果读取的数据在同一个CacheLine,就存在缓存伪共享的问题。
对象被放入一个CacheLine中,根据MSEI协议,其中一个属性改变,其他所有没有改变的属性也变得不可共享。
填充Cache Line缓存块
通过填充对象,将对象中常被改变的属性和不常改变的属性分开到不通缓存Cache Line中。避免缓存的伪共享。
未填充对象:
public class DataPadding{ int value; long modifyTime; boolean flag; long createTime; char key; }
对象结构:
# Running 64-bit HotSpot VM. # Using compressed oop with 3-bit shift. # Using compressed klass with 3-bit shift. # Objects are 8 bytes aligned. # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] com.hyr.jol.demo.JOLSample_02_Alignment$DataPadding object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 4 int DataPadding.value N/A 16 8 long DataPadding.modifyTime N/A 24 8 long DataPadding.createTime N/A 32 2 char DataPadding.key N/A 34 1 boolean DataPadding.flag N/A 35 1 (alignment/padding gap) 36 4 com.hyr.jol.demo.JOLSample_02_Alignment DataPadding.this$0 N/A Instance size: 40 bytes Space losses: 1 bytes internal + 0 bytes external = 1 bytes total
填充后对象:
public class DataPadding{ long a1,a2,a3,a4,a5,a6,a7,a8;//防止与前一个对象产生伪共享 int value; long modifyTime; long b1,b2,b3,b4,b5,b6,b7,b8;//防止不相关变量伪共享; boolean flag; long c1,c2,c3,c4,c5,c6,c7,c8;// long createTime; char key; long d1,d2,d3,d4,d5,d6,d7,d8;//防止与下一个对象产生伪共享 }
对象结构:
# Running 64-bit HotSpot VM. # Using compressed oop with 3-bit shift. # Using compressed klass with 3-bit shift. # Objects are 8 bytes aligned. # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] com.hyr.jol.demo.JOLSample_02_Alignment$DataPadding object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 4 int DataPadding.value N/A 16 8 long DataPadding.a1 N/A 24 8 long DataPadding.a2 N/A 32 8 long DataPadding.a3 N/A 40 8 long DataPadding.a4 N/A 48 8 long DataPadding.a5 N/A 56 8 long DataPadding.a6 N/A 64 8 long DataPadding.a7 N/A 72 8 long DataPadding.a8 N/A 80 8 long DataPadding.modifyTime N/A 88 8 long DataPadding.b1 N/A 96 8 long DataPadding.b2 N/A 104 8 long DataPadding.b3 N/A 112 8 long DataPadding.b4 N/A 120 8 long DataPadding.b5 N/A 128 8 long DataPadding.b6 N/A 136 8 long DataPadding.b7 N/A 144 8 long DataPadding.b8 N/A 152 8 long DataPadding.c1 N/A 160 8 long DataPadding.c2 N/A 168 8 long DataPadding.c3 N/A 176 8 long DataPadding.c4 N/A 184 8 long DataPadding.c5 N/A 192 8 long DataPadding.c6 N/A 200 8 long DataPadding.c7 N/A 208 8 long DataPadding.c8 N/A 216 8 long DataPadding.createTime N/A 224 8 long DataPadding.d1 N/A 232 8 long DataPadding.d2 N/A 240 8 long DataPadding.d3 N/A 248 8 long DataPadding.d4 N/A 256 8 long DataPadding.d5 N/A 264 8 long DataPadding.d6 N/A 272 8 long DataPadding.d7 N/A 280 8 long DataPadding.d8 N/A 288 2 char DataPadding.key N/A 290 1 boolean DataPadding.flag N/A 291 1 (alignment/padding gap) 292 4 com.hyr.jol.demo.JOLSample_02_Alignment DataPadding.this$0 N/A Instance size: 296 bytes Space losses: 1 bytes internal + 0 bytes external = 1 bytes total
JDK1.8解决缓存伪共享
JDK1.8中增加了Contended注解方式来解决缓存伪共享问题。
在JDK1.8中,新增了一种注解@sun.misc.Contended,来使各个变量在Cache line中分隔开。注意,jvm需要添加参数-XX:-RestrictContended才能开启此功能
未填充对象:
public class DataPadding{ int value; long modifyTime; boolean flag; long createTime; char key; }
对象结构:
# Running 64-bit HotSpot VM. # Using compressed oop with 0-bit shift. # Using compressed klass with 0-bit shift. # Objects are 8 bytes aligned. # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] com.hyr.jol.demo.JOLSample_02_Alignment$DataPadding object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 4 int DataPadding.value N/A 16 8 long DataPadding.modifyTime N/A 24 8 long DataPadding.createTime N/A 32 2 char DataPadding.key N/A 34 1 boolean DataPadding.flag N/A 35 1 (alignment/padding gap) 36 4 com.hyr.jol.demo.JOLSample_02_Alignment DataPadding.this$0 N/A Instance size: 40 bytes Space losses: 1 bytes internal + 0 bytes external = 1 bytes total
使用Contended注解:
public class DataPadding { @sun.misc.Contended("group1") int value; @sun.misc.Contended("group1") long modifyTime; @sun.misc.Contended("group2") boolean flag; @sun.misc.Contended("group3") long createTime; @sun.misc.Contended("group3") char key; }
对象结构:
# Running 64-bit HotSpot VM. # Using compressed oop with 0-bit shift. # Using compressed klass with 3-bit shift. # Objects are 8 bytes aligned. # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] com.hyr.jol.demo.JOLSample_02_Alignment$DataPadding object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 12 (object header) N/A 12 4 com.hyr.jol.demo.JOLSample_02_Alignment DataPadding.this$0 N/A 16 128 (alignment/padding gap) 144 4 int DataPadding.value N/A 148 4 (alignment/padding gap) 152 8 long DataPadding.modifyTime N/A 160 128 (alignment/padding gap) 288 1 boolean DataPadding.flag N/A 289 135 (alignment/padding gap) 424 8 long DataPadding.createTime N/A 432 2 char DataPadding.key N/A 434 6 (loss due to the next object alignment) Instance size: 440 bytes Space losses: 395 bytes internal + 6 bytes external = 401 bytes total
如果想深入了解,可以看下关于CPU Cache、Linux Cache相关的知识。
项目输出对象结构用的JOL。相关技术可以参考我的Github项目:https://github.com/huangyueranbbc/JVM_AGENT_DEMO
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
java异常处理01
java异常处理高级技巧 什么是Java异常? 当Java程序的正常行为被意外行为中断时,会发生故障。这种故障被称为异常。例如,程序尝试打开文件以读取其内容,但该文件不存在将产生异常。Java将异常分为几种类型,所以让我们考虑每一种类型。 检查异常 Java将(例如FileNotFoundException, IOException)引起的异常分类为已检查的异常。Java编译器会检查这些异常,并且在异常发生的位置要求进行捕获处理或者向上抛出(throws)。需要注意的是检查异常属于编译器的行为,要求你必须在代码中捕获或向上抛出(throws)。 运行时(非检查)异常 例如程序进行强制转换(cast),这种可能存在转换失败的异常就是另一种异常。即运行时异常(RuntimeException)。和检查不同,编译器不会检查你在代码中是否进行处理或抛出。运行时异常通常来自编写的不良代码,因此应由程序员修复。 错误(Error) 指一些非常严重,通常无法进行修正必须要重启程序的异常。例如, 尝试从JVM分配内存,但没有足够的可用内存来满足请求(OutOfMemoryError)。运行时尝试调用加...
- 下一篇
[积德篇] 如何少写PHP "烂"代码
写给初生牛犊不怕虎的童鞋们,大佬可随意摘看 本章基于PHP Laravel 前言 经常会有人问 目录如何设计比较好? 代码如何分布好? 怎么写一个可维护的项目? “烂”项目我也没少写,以下是参考互联网各大佬的文章总结及个人开发经验而来. Controller Controller顾名思义是控制器,在入门PHP的时候,就知道Controller代表MVC中的C层,MVC本身的概念就代码分离,教你如何如何将业务分开,但面临着业务的不断发展,代码的复杂度也随之提高,功能与功能之间的链接错综复杂,最后你的MVC就变成了下图,所以仅仅依托MVC的设计思想已经无法支撑不断发展的业务。 现在我们将Controller的任务和能力重新定义,控制器仅仅控制Http Reqeust的请求,这样就符合了SOLID 单一功能原则. 直接将业务代码写在Controller中,会使得代码及其臃肿,不易于维护和扩展 <?php namespace App\Http\Controller; class UserController extends Controller{ public function regi...
相关文章
文章评论
共有0条评论来说两句吧...