Cache Line 缓存行 内存行对齐

转载:https://www.jianshu.com/p/344592b9f774(侵删)

Cache Line可以简单的理解为CPU Cache中的最小缓存单位。目前主流的CPU Cache的Cache Line大小都是64Bytes。假设我们有一个512字节的一级缓存,那么按照64B的缓存单位大小来算,这个一级缓存所能存放的缓存个数就是512/64 = 8个。具体参见下图:

image.png

代码示例:

public class CacheLine {

  private static class T {
    public volatile long x = 0L;//long类型占据8个字节

  }
    public static T[]  arr = new T[2];
  static {
    arr[0] = new T();
    arr[1] = new T();//两个数组紧挨着保证在内存中也是挨在一起的
  }

  public static void main(String[] args) throws Exception{
    Thread t1 = new Thread(() -> {
      for (long i = 0; i<10000000L; i++) {
        arr[0].x = i;//修改一千万次
      }
    });
    Thread t2 = new Thread(() -> {
      for (long i = 0; i<10000000L; i++) {
        arr[1].x = i;//修改一千万次
      }
    });
    final long start = System.currentTimeMillis();
    t1.start();
    t2.start();
    t1.join();//让t1线程先执行完
    t2.join();//让t2线程执行完
    System.out.println(System.currentTimeMillis() - start);//join 保证主线程的这段代码最后执行

  }
}

执行结果为 300ms左右
上面代码中 arr[0] 和 arr[1]会在同一个cache line中,而每个cache line 是cpu 读入的最基本单位,在我们使用vaolatile 之后线程t1对x的1000000万次修改都要刷新内存通知t2,而同样t2对x的修改也要告诉t1。这样就会存在频繁的cache line 和内存的刷新读取。
如果我们将 对x的修饰的valitile去掉执行结果为10ms左右
使用缓存行对其的方式代码示例:

public class CacheLine {
 private static class parent {
   public volatile long p1,p2,p3,p4,p5,p6,p7;//创建七个long 基本数据类型的成员变量占据56个字节
 }
 private static class T extends parent{
   public volatile  long x = 0L;//long类型占据8个字节

 }
  public static T[]  arr = new T[2];
  static {
    arr[0] = new T();
    arr[1] = new T();//两个数组紧挨着保证在内存中也是挨在一起的
  }

  public static void main(String[] args) throws Exception{
    Thread t1 = new Thread(() -> {
      for (long i = 0; i<10000000L; i++) {
        arr[0].x = i;//修改一千万次
      }
    });
    Thread t2 = new Thread(() -> {
      for (long i = 0; i<10000000L; i++) {
        arr[1].x = i;//修改一千万次
      }
    });
    final long start = System.currentTimeMillis();
    t1.start();
    t2.start();
    t1.join();//让t1线程先执行完
    t2.join();//让t2线程执行完
    System.out.println(System.currentTimeMillis() - start);//join 保证主线程的这段代码最后执行

  }
}

执行结果为 100ms左右
现成t1一次读入x 包括p1p2p3p4p5p6p7的所有变量64个字节刚好占据一个缓存行,线程t2 也是如此,所以他们对变量x的修改都不用刷新内存通知对方提高了性能。
为什么这里不包括对象头的那部分呢,因为对相头不是使用的部分,不会读入缓存,我们用到的只是成员变量
总结为cpu对于内存的读入到缓存的数据是按照缓存行的大小(64k)来读取的。

访问不同缓存区所需要的的时钟周期:
在这里插入图片描述
访问普通内存所需的时钟周期比访问L1、L2、L3大很多,编程时需要注意这一点。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值