【JAVA】数据结构和CPU的那点儿事儿

写在前面的

   有时候,实现同样的功能(例如检索),方法不一样,可能最后相同的结果所花费的时间却不一样。这里先排除可能是由于不同的算法导致的结果在时间或者空间复杂度上造成的差异所导致的情况。我们单就数据结构和内存本身而言,不同的数据结构,或者简单明了一点,方法体中声明不同的数据类型,或者同一个数据类型不同的写法,都可能导致最终执行时间的不同。

CPU

   想要了解为什么会有这样的区别产生,我们先要了解一下CPU。在这里我们先不解读JVM和和OS之间的交互,否则又该腰疼了23333333。

  • 众所周知,CPU拥有三级缓存,根据型号的不同这三级缓存的大小也不一样,计算单元的算力也就不一样。在计算机系统原理中,我们接触过“寻址”这一概念,CPU内部也一样,它将最常用的数据放到了一级缓存中,离自己最近;将稍微常用的放到了二级缓存中,离自己稍微远一些;将稍微不常用的放到了三级缓存中,离自己最远。(这里的远近当然指的是在CPU内部,和内存以及硬盘无关)
  • 一般来讲,CPU的一级缓存延迟在2~3ns;二级缓存为10~15ns;三级缓存为20~30ns。所以算下来,我们CPU平均的执行时间为40ns左右。(这当然和CPU的微架构有关系)。
  • 缓存一致性问题,和我们平时所涉及到的数据库或者应用缓存中的数据一致性问题相同。在多核心CPU中,各个Core都要从缓存中存取数据,所以在CPU内部都一套自己的“管理办法”来对各个Core的数据存取做出标记,来保证数据的一致性。

   简单的了解过CPU的高速缓存之后,我们来聊一聊缓存寻址以及数据存储。下面我们来结合一个例子说明一下不同的声明方式,对计算时间的影响。

  • 我们在遍历一个数组的时候,(以FOR循环为例)如果是一维数组,很简单,一个FOR循环就可以搞定。而且一维数组在CPU内部处理的时候也是“一整片”缓存空间连续存储,这样可以节省寻址所花费的时间。

  • 好了,接下来,重头戏来了,当我们的数组维度上升到二维,假如我们都需要数组中容纳一百个数,我们通过两种方式来声明这个数组。

//声明两个数组
int x[][] = new int[100][1];
int y[][] = new int [1][100];
//进行FOR循环,输出每个数
For(int i=0;i<100;i++){
    For(int j=0;j<1;j++){
        System.out.println(x[i][j]);
    }
}
For(int i=0;i<1;i++){
    For(int j=0;j<100;j++){
        System.out.println(y[i][j]);
    }
}

我们可以看到,在OOP的层面上,这两个循环的时效性并没有区别,无论怎么看,这俩个FOR循环的时间复杂度是一样的。但是如果数据量过大,你就会发现,这两个循环的执行速度并不一样,后者会快于前者。为什么呢?

  • 因为在计算机缓存中,我们有一个叫“Cache Line”的概念。我们可以简单的理解为“内存区域的连片存储/连续的一段内存区域。由于JAVA在内存中分配的原则是首先分配第一维,然后在分配二维子数组,所以单个数组的内存空间是连续的。言外之意,不同的子数组之间的内存空间是不在一起的,分段的。既然每个子数组并不连续的存放在内存中,那么就涉及到寻址的问题了,一旦涉及到寻址,那么时间消耗不就增大了吗?
  • 我们通过上面的例子来说明一下:对于X[i][j]数组当我们遍历了X[1][1]之后,就需要重新在内存中进行对”X[2][1]”的寻址;而对于Y[i][j]数组而言,在遍历了Y[1][1]之后,并不需要重新寻址,因为剩下的Y[1][2]、Y[1][3]……等等均在声明的时候被连续存储在了一段连续的空间内,所以不用涉及寻址问题。

Cache Line

   经过了上面的描述,我们可以对Cache Line有个基本的认识。

  • 在内存分配中,我们有两段空间分别存储了X[][]与Y[][],在CPU中,Cache Line操作会将一些数组元素一次性全部拿到高速缓存中备用。这样当遍历Y数组的时候,Cache Line将其一次性全部带入高速缓存,供CPU直接调用;而对X数组则需要反复几次才可以遍历完全。

  • Cache Line就是一个“一次拿一批信息去交由CPU处理的一个机制”。

总结

   可见,对于数据结构的优化,如果不懂得最底层的原理,那优化起来岂不是无从下手?相反,如果对计算机的底层与程序之间的交互原理积累多了,那对于框架的优化而言,更是如虎添翼。功底,还是很重要的嘛。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值