数据结构是如何装入CPU寄存器的?
我们在之前很多文章的讲解中涉及了CPU与寄存器,然后有同学问了这样一个问题:既然CPU内部的寄存器数量有限,容量有限, 那么我们使用的庞大的数据结构是怎样装入寄存器供CPU计算的呢 ?
这篇文章就为你讲解一下这个问题。
内存与数据
真正有用的程序是离不开数据的,比如一个int、一个float等,这些都是非常简单的数据。
当然也有非常复杂的数据,这样的数据通常在内存中以数据结构的形式组织起来,比如你创建了一个数组、一个链表、创建了一棵树、一张图,就像这样:
那么很显然 这些数据 存放在内存中,而且这些数据在不同的场景下有不同的大小,从数B、数KB到数百GB都有可能,与此同时,CPU内部的寄存器数量是固定的,容量也是极其有限的,那么CPU是如何利用有限的资源操作庞大的数据结构呢?
要回答这一问题,我们需要要认识一位农夫, 因为他不生产数据,他只是数据的搬运工 ,这位农夫就是…
搬运数据的机器指令
你没有看错,这位农夫就是我们之前多次提到的机器指令。
机器指令中除了负责逻辑运算、执行流控制、函数调用等指令外,还有一类指令,这类执行只负责和内存打交道,典型的就是精简指令集架构中的Load/Store机器指令,即内存读写指令( 复杂指令集没有单独的内存 读写指令)。
原来,从宏观上看的话,存放在内存中的数据,比如一个数组,可能会非常庞大,但是具体到代码,每一个步骤操作的数据又会非常简单,就像这样: int* huge_arr = new int[1 * 1024* 1024 *1024];
我们创建了一个长度为1G的数组,每个int 4字节,则这个数组的大小就是4GB,这显然是一个很庞大的数组。
对于这样的数据,我们通常都会怎么使用呢?
最常见的情况可能是遍历一边,然后对每个字符进行一个简单操作,这里以计算数组之和为例: long int sum = 0; for (int i = 0; i < 1 * 1024* 1024 *1024; i++) { sum += huge_arr[i]; }
虽然整个数组多达4GB, 但具体到每一步我们一次只能操作一个元素 ,就像这里的:
sum += huge_arr[i];
这行代码翻译成机器指令可能是这样的,我们假设此时i为100:
load $r0 100 ( $r2 )
add $r1 $r1 $r0
(注意,实际当中编译器不会傻傻的生成100这样的常数,这里代码仅用来方便讲解问题)。
第一行指令中数组首地址存放在寄存器r2中,100($r2)表示数组首地址+100,这样我们就能得到huge_arr[100]的地址了,然后将该地址中的值利用load指令加载到寄存器r0中。
第二行就简单多了,r1寄存器中保存的是sum的值,该行指令执行过后r1中的值就已经加上了huge_arr[100]。
现在你应该能看出来了吧,虽然我们不能把整个数组加载到寄存器供CPU计算,但这其实是没有必要的,因为我们一次只能操作数组中的一个元素, 我们只需要把这一个元素加载到寄存器就足矣了 。
对于其它复杂的数据结构也是同样的道理,无论多么复杂的数据,代码对其一次的操作都是很简单很微小的,这一微小的操作使用的基本元素都可以通过内存读写指令加载到寄存器,修改完后再写回内存。
编译器
现在你应该知道了为什么CPU内部那么少的寄存器能操作内存中庞大的数据结构,实际上由于内存中的数据要远大于CPU寄存器的容量,因此 编译器必须精心挑选,好让那些经常使用的数据放到寄存器中的时间更长一点, 这样可以减少内存读写次数。
在上面的示例中,r2寄存器保存的是huge_arr这个数组在内存中的起始地址,那么这个数据应该放到寄存器中,因为后续遍历到的每一个元素都要用到该地址,这项工作就是编译器来完成的。
编译器把那些经常使用的数据放到寄存器,剩下的放到内存中,然后利用内存读写指令在寄存器和内存之间来回搬运数据。
总结
通过本文不难发现,实际上我们没有必要一次性把整个数据全部装到CPU寄存器中,而是用到哪些才装载哪些。
在最细粒度的操作中,依赖的操作数都可以直接加载到内存,这通常是由内存读写机器指令来完成的。
我是小风哥,希望这篇文章对大家理解CPU与寄存器有所帮助。
来源:https://mp.weixin.qq.com/s?__biz=Mzg4OTYzODM4Mw==&mid=2247486030&idx=1&sn=83d02968fbf0d5298a021616f4571b76&utm_source=tuicool&utm_medium=referral
快递面单上的二维码是广告还是陷阱?图视觉中国羊城晚报记者林曦实习生曹轩今年双11购物节以约8894亿元的交易总额圆满落幕,其中天猫完成交易额约5403亿元,京东完成交易额约3491亿元。狂欢过后,海量的快递包裹陆续
骁龙8Gen1赢了?消息称天玑9000不支持毫米波5G市场主要在国内在骁龙8Gen1发布之前,联发科抢先几天发布了天玑9000,这是首款台积电4nm工艺5G处理器,也升级了ARM的X2超大核A710GPU等架构,跑分性能也超过百万了。与联发科以往的
发明手机字词典加翻译的手机软件功能说到手机,很多人会想到用手机来远程通话,还有的人利用手机购物,还有的用手机玩游戏,这些都可以。手机的软件各种各样,其主要工具不妨有这几类,电话,拍照,计算器,镜子,转账,灯等,这些
入门级单反的画质很差吗?你问,入门级单反的画质真的很差吗?以我这么多年的使用经历,我用过很多入门级的数码单反,从佳能300D开始,我觉得,在同时代,入门级数码单反的画质其实都是够用的了,绝对不能叫做很差。
6核性能小钢炮!iPhoneSE3发布时间曝光,售价很心动今年9月份苹果正式推出了全新一代iPhone13系列,不过有部分用户对于iPhone13并不是太感兴趣,希望苹果能更新一下iPhoneSE系列,距离上一代iPhoneSE2已经有很
2021数字基建论坛在北京召开12月4日下午,由人民网主办安迈云协办的2021数字基建论坛在北京召开。本次论坛以夯基业筑未来为主题,来自政产学研的众多嘉宾齐聚一堂,共话数字经济高质量发展路径。中国科学院大学应急
CEffective读书笔记条款4条款4尽量使用C风格的注释旧的C注释语法在C里还可以用,C新发明的行尾注释语法也有其过人之处。例如下面这种情形if(ab)inttempaswapaandbabbtemp假设你出于
华为麒麟芯片笔记本曝光搭载5nm麒麟处理器中关村在线消息根据网友爆料,华为即将推出擎云L420笔记本电脑,据称该笔记本电脑将搭载麒麟9006C处理器,并运行统信UOS系统。根据爆料消息,华为擎云L420将搭载由5nm工艺打
EffectiveC读书笔记条款2条款2尽量用而不用stdio。hscanf和printf很轻巧,很高效。尽管他们很有用,但还是可以做些改进的。尤其是,他们不是类型安全的,而且没有扩展性(它们是C的基石)。scan
EffectiveC读书笔记条款1条款1尽量用const和inline而不用define这个条款最好称为尽量用编译器而不用预处理。因为define经常被认为好像不是语言本身的一部分。这是问题之一。另外,再看下面的语
Go语言核心36讲(Go语言实战与应用二十一)学习笔记43bufio包中的数据类型(下)在上一篇文章中,我提到了bufio包中的数据类型主要有ReaderScannerWriter和ReadWriter。并着重讲到了bufio。Rea