聊聊对程序的局部性原理的新认知

      这篇文章涉及到的内容不多,所以篇幅也不会很长,主要是学习程序的局部性原理,涉及到java对象和数组相关的内容,让对数组这种分配连续的内存空间存储数据的数据结构和java对象以及对象的引用有更清晰明确的理解。写这篇文章也是在坐地铁上班路上看技术文章的时候学习到的,所以记录下来,阅读完这篇文章之后不知道有没有共鸣的朋友。

前言

       正文之前先说点闲话吧,最近没有更新写文章,主要原因还是自己不是很在状态,三月份入职了新公司刚好一个月结果因疫情影响被裁(是不是很悲催),失业了两周又重新找到一家公司然后四月底入职了,这段时间也在忙着熟悉新公司的项目,现在回过来看那段时间也确实不好找工作因为疫情的环境。这将近半年的换工作经历让我成长了好多,非常幸运我现在已经养成了持续学习的心态和习惯了,能够让自己不断提升自己的技术认知和技术能力,这对于搞技术的人来说是非常重要的,我毕业后的第一份工作经历让我没有很大的进步,更多的是在做没有多大技术含量并且没完没了的CRUD,也庆幸自己这段时间经历很多碰壁,碰的多了才更清楚自己的现状以及过去自己做的不足的地方,才能更早做出改变,更加明确今后在技术这条路上该如何走,目前的我算上实习经历工作两年多一点,相比优秀的人我还很菜很垃圾,但是我坚信都还不晚!下面这张图让我感触颇深,确实,我在大学一直到工作一年多的这段时期,一直停留在愚昧山峰,庆幸我在往绝望之谷前进, 我想很快就能到达谷底了!这张图不知道是否对看文章的你有所感触呢?

正文

       说了那么多闲话,开始正文。程序的局部原理:指程序在运行的过程中,在一段执行的时间内会限定在一个局部的范围内,这个局部性有两个方面,一个是时间局限性,另一个是空间局限性。时间局部性指的是程序中的某条指令一旦被执行,不久之后这条指令很可能再次被执行;如果某条数据被访问,不久之后这条数据很可能再次被访问。而空间局部性是指某块内存数据一旦被访问,不久之后这块内存附近的内存数据也很可能被访问。我们知道计算机有磁盘、内存、高速缓存,内存和高速缓存目的是为了提高CPU访问数据速度的瓶颈,尽量降低CPU对数据的查询时间,CPU在切换到某个线程运行的时候,涉及到的运行数据如果没有在高速缓存中(这里我们简化,不考虑L1L2高速缓存,都看成高速缓存),就会去内存中查找,如果内存也没有就会去磁盘中查找,然后再回写更新到内存和高速缓存,这个过程相对于CPU来说是非常耗时的,最理想的状态应该就是整个CPU运行过程中需要的数据都在高速缓存中,这样就不涉及到去内存或者磁盘查找数据了,但是这是不可能的。CPU的缓存机制就利用了程序的局部性原理,CPU从内存中加载数据X的时候,会将需要的数据X以及顺带会把X所在内存位置周围的数据一起缓存到高速缓存中,也就是说如果程序能够很好地体现出局部性原理,也就能更好地利用 CPU 的缓存,从而提升程序的性能。

       现在我们再来看看数组这样的数据结构,我们知道在创建数组的时候就是会分配一块连续的内存空间,这也是数组可以随机查找能力的原因,数组每个元素空间大小相同,又是连续的内存空间,那我们就可以通过数组所在的内存地址起始偏移量offset + i * size得到对应下标 i 的元素了,所以我们使用数组的时候对CPU缓存是比较友好的。接下来的内容就是我写这篇章的目的了,因为在这之前的内容我是事先就知道的。我用一个简单的例子,下面代码分别开辟了一个int基本数据类型的数组,和一个自定义类Other类型的数组链表,其实ArrayList底层就是数组嘛,然后分别给两个集合中添加对应元素,很简单,看下面代码:

import java.util.ArrayList;
import java.util.List;

public class Test {

    static class Other{
        int num;
        public void setNum(int num){
            this.num = num;
        }
    }


    public static void main(String[] args) {
        int[] arrA = new int[10];

        List<Other> list = new ArrayList(100);

        for (int i = 0; i < 10; i++){ // 添加是个元素
            arrA[i] = i;  // 基本数据类型的数组中添加数字

            Other newObject = new Other();
            newObject.setNum(i);
            list.add(newObject);
        }
    }
}

       我现在想问你的是,两个数组都有利于CPU的缓存吗?答案是否定的,我们知道基本数据类型确实都存放在数组所在开辟的连续空间当中,这样整个数组被加载到高速缓存之后,在访问其他数据的时候确实能够提供高速缓存的命中率,但是本例子中的list中的数组有利于CPU缓存吗?NO,因为数组存放的是每个Other实例对象的引用,而实际的对象其实可能分配在内存不连续的地址中,所以CPU拿到引用之后还得去内存中加载对应的对象信息!

       这里我们衍生说一下我们使用的ArrayBlockingQueue,底层也是对应的数组,数组的元素类型是我们自定义的对象类型,如果使用这样的队列并不能起到更细节的性能考虑,可以使用Disruptor,有兴趣可以看下其实现原理,我也是在看Disruptor文章的时候才认知到上面一点!

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值