缓存伪共享问题以及解决方案缓存行填充
缓存伪共享
共享对象存在同一个缓存中,由于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业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Docker应用部署
mysql 部署1)拉取mysql镜像 docker pull centos/mysql-57-centos 2)创建容器 docker run -id --name=mysql -p 33306:3306 -e MYSQL_ROOT_PASSWORD=123456 centos/mysql-57-centos -p 代表端口映射,宿主机端口:容器运行端口-e 添加环境变量MYSQL_ROOT_PASSWORD 是root的登录密码3)远程连接mysql宿主机端口(192.168.154.201:33306) root 123456tomcat部署1)拉取镜像 docker pull tomcat 2)创建容器-p创建地址映射 docker run -id --name=mytomcat -p 9000:8080 -v /usr/local/webapps:/usr/local/tomcat/webapps tomcat 3)在/usr/local/webapps 创建1.html hello world 4)访问192.168.154.201:9000/1.htmlNginx部署1)...
- 下一篇
Redis 在项目中合理使用经验总结
背景1.Redis是一个开源的内存数据结构存储系统。2.可以作为数据库、缓存和消息中间件使用。3.支持多种类型的数据结构。4.Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence)。5.通过 Redis 哨兵(Sentinel)和 Redis 集群(Cluster)的自动分区,提供高可用性(high availability)。 基本数据类型字符串(strings) 1、string 的过期时间在重新设置值之后会被清除 127.0.0.1:6379> set hello 3OK127.0.0.1:6379> get hello"3"127.0.0.1:6379> ttl hello(integer) -1127.0.0.1:6379> expire hello 3000(integer) 1127.0.0.1:6379> set hello 4OK127.0.0.1:6379> tt...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Windows10,CentOS7,CentOS8安装Nodejs环境
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS关闭SELinux安全模块
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2全家桶,快速入门学习开发网站教程