首先给你们讲个段子:html
2015年开网吧,买了 DDR4 8g 内存条400多根,一根180块,今年2017年,网吧赔了20多万,昨天我把网吧电脑全卖了。内存条600一根,竟然赚回了我网吧的钱,感谢三星,感谢人民,感谢党。。。java
今年以来,内存条价格暴涨,已经跃升为新的新一代理财产品,因此今天就和你们讨论一下内存的话题,主要内容就是在程序运行过程当中,内存的做用以及如何与CPU,OS交互。git
咱们先来讨论:计算机的运行到底是在作什么?来看一下经典的冯诺依曼结构。计算机科学虽然飞速发展了几十年,可是依旧遵循冯诺依曼结构。程序员
图1:冯诺依曼结构github
数学家冯诺依曼提出的 体系结构包含如下几个要点:算法
- 把程序自己看成数据来对待,程序和该程序处理的数据用一样的方式储存。
- 计算机的数制采用二进制。
- 计算机应该按照程序顺序执行。
咱们根据这张图进行思考就能够获得一个结论,所谓计算机处理任务,就是根据输入内容,数据/程序从存储器送往CPU进行处理,而后再将结果输出。编程
关于程序与数据,数据就是一首MP3歌曲, 程序就是用来控制解析播放这首歌的代码,从底层来说就是供CPU运行的指令.总之在计算机当中它们都是0和1,不过为行文方便,咱们直接简称为数据或程序或指令, 将它们理解为同一个意思,毕竟它们都属于0和1组成的流,这个能够根据上下文来理解。数组
本文讨论的主要内容,就是 存储器部分,为何计算机须要存储器部分?这是显而易见的,我写好了程序,或者下载了一部电影,确定得有个地方放啊。这样从此须要的时候,才能运行程序或者看电影啊。缓存
咱们思考一下,这个存储器应该具有什么样的特色。服务器
关于这个存储器,咱们大概想出了一个理想的存储器应该具有的的5个特色。
可是有句话说的好。理想很丰满,显示很骨感。一个屌丝在纸上列出了几十条他理想女朋友的标准,可是他能如愿吗?
先说结论,彻底知足咱们理想条件的存储器目前还没发明出来呢。目前的半导体工业只能造出部分符合条件的存储器,可是彻底知足以上几条标准的,对不起,将来也许能作到,可是起码目前作不到。
因此这也是目前计算机系统存储器系统比较复杂的缘由,区分为内存,硬盘,光盘等不一样的存储器,若是有个完美的符合咱们理想条件的存储器,直接使用这种存储器就行了。
先看看看咱们最多见的存储设备:磁盘。足够稳定;有电没电都正常存储;容量也较大;价格也能够接受,因此磁盘是咱们最多见的存储设备。
磁盘就是咱们存储器的表明了。
为了行文方便,文中直接将存储器用磁盘来代替了,一来你们对磁盘比较熟悉,二来磁盘也是最多见的存储设备。相似flash,SD卡,ROM等从广义上来说,也能够称为磁盘。由于它们的做用都是存储数据,掉电后不丢失。(这在下面文章中也会讨论到)
磁盘和硬盘什么关系呢?实际上是同一个意思。硬盘是最多见的磁盘类型。在很早以前,计算机使用软盘存储数据,因此那种软盘也被称为 磁盘,不过软盘都早就被历史淘汰了,(电脑硬盘分区从C盘开始,就是由于AB盘是以前软盘的编号)。因此如今咱们说磁盘,直接理解成硬盘就行了。
在咱们软件当中,有个概念叫作数据持久化,意思就是说将数据存储起来,掉电以后不丢失,这其实就是存储在磁盘上面。
因此如今咱们理解的计算机运行就是这样一个过程:将数据从磁盘送往CPU,供CPU进行计算,并将结果输出。
由于咱们这片文章就是 讨论 内存,存储等问题,因此关于 输入设备,输出设备之类的,就再也不涉及和讨论。
而后咱们再简短来讨论CPU的发展历史。
世界上第一台计算机是1946年在美国诞生的ENIAC,当时CPU仍是使用笨重的电子管,后面的故事依次是贝尔实验室发明了晶体管,TI的工程师又发明了集成晶体管,IBM研发成功首款使用集成电路的计算机,IBM360, 后面 就是仙童八叛徒与intel,AMD的故事了。这段很著名的IT故事,咱们再也不累述了。伴随着世界上第一款商用处理器:Intel4004的出现,波澜壮阔的摩尔定律开始了。
当时负责IBM 360 操做系统开发的那个项目经理,根据该项目经验, 写了一本经典著做《人月神话》,也有其余参与者根据该项目经验,立传出书了,因此当时那批人都是大牛。
摩尔定律:当价格不变时,集成电路上可容纳的元器件的数目,约每隔18-24个月便会增长一倍,性能也将提高一倍。
半导体行业开始腾飞了。CPU上集成的晶体管数量愈来愈多。 intel i9的制程工艺已经到了14nm。因此CPU的执行速度也愈来愈快。
固然,摩尔定律也快到尽头了,根据量子力学,2nm是理论极限值。线宽不能再细了,低于2nm,隧穿效应就会产生干扰。
闲扯了一段CPU的发展历史,想说明的是,如今的CPU集成度愈来愈高,速度也愈来愈快。每秒钟能执行的指令也愈来愈多。(若是不知道指令,汇编之类的啥意思,看一下个人的另外一篇文章关于跨平台的一些认识,不然下面的内容看着也有难度)。
CPU的做用就是去执行指令(固然,也包括输出结果等,本文只讨论和存储器相关,因此不扯其余的),而且尽量的以它的极限最高速度去执行指令,至于具体的执行过程,作过单片机或者学过微机原理的应该比较清楚。就是伴随着时钟周期滴滴答答的节奏,CPU踏着拍子来执行指令。
至于CPU的指令集,那就是Intel的架构师们的工做,总之,CPU认识这些指令,而且能执行运算。(别忘记了冯诺依曼体系结构那张图)。对于这些指令,可是CPU采起了各类措施来加快执行过程(也能够理解为加快它的计算速度)。好比有如下几种常见的措施:
- 流水线(pipeline)技术:有电子厂打工经历的读者确定很熟悉这个流水线模式。CPU的流水线工做方式和工业生产上的流水线概念同样。就是将一个指令的执行过程也分解为多个步骤,CPU中的每一个电路只执行其中一个步骤,这样前赴后继加快执行速度。CPU中多个不一样功能的电路单元组成一条指令处理流水线,而后将一条指令分红几个步骤后再由这些电路单元分别执行。在执行过程当中,指令源源不断的送往CPU。让每一个电路单元都不闲着,这样就大大的加快了执行速度。
- 超线程(Hyper-Threading)技术:对于超线程,百度百科的解释我都没看懂,可是大概原理就是这样的。CPU在进行线程切换的时候,要执行 切换各类寄存器状态等一些操做。把第一个线程的各类寄存器状态写回缓存中保存,而后把第二个线程的相关内容送到各类寄存器上。该过程必不可少,不然待会再将第一个线程切换回来时,不知道该线程的各个状态, 那还怎么接着继续执行呢?也正由于如此,因此这个过程比较慢,大概须要几万个时钟周期。因此后来作了这样的设计,把每一个寄存器等都多作一个,就是多作一组寄存器(也包括一些其余相关电路等),,CPU在执行A线程时,使用的第一组寄存器,切换到B线程,直接使用第二组寄存器,而后再切换A线程时,再使用第一组寄存器。,CPU就不用再傻傻的等着寄存器值的切换,线程切换只须要几个时钟周期就够了。对于普通的执行多任务的计算机,CPU线程切换是个很是频繁的操做,因此使用该技术就会节省大量的时钟周期。也就是至关于加快了CPU的执行速度。这就是CPU宣传参数中所谓的四核八线程的由来,其实就是超线程技术。(每一个核多作一组寄存器等电路当然会占用宝贵的空间,可是它带来的优势远远大于缺点)。
- 超标量技术:CPU能够在每一个时钟周期内执行多个操做,能够实行指令的并行运算。
- 乱序执行: 咱们认为程序都是顺序执行的。可是在CPU层面上,指令的执行顺序并不必定与它们在机器级程序(汇编)中的顺序同样。好比
a = b+c; d++;
这两个语句 不按照顺序执行也不会影响最终结果。固然这只是在CPU执行指令的层面,在程序员们看来,依旧认为程序是顺序执行的。
前面扯了那么多,就是为了说明CPU的执行速度很快。虽然每条指令的执行时间须要几个时钟周期到几十个时钟周期不等。可是CPU采用了种种技术来加快执行过程。因此平均执行一条指令只须要一个周期。而如今CPU主频都那么高。好比i7 7700K主频达到了 4.2G。这也就意味着,每一个core每秒钟大约能够执行4.2亿条指令。那四个core呢?
咱们讨论完CPU如此快的执行速度,咱们再来讲咱们常见的存储设备-机械硬盘。
图2:机械硬盘结构
机械硬盘的结构就再也不具体的讨论了。它让我想起了民国电影中那种播放音乐的唱片机。
带机械硬盘的电脑,在使用过程当中,若是机箱被摔了,可能后果很严重,就是由于可能会把机械硬盘的那个读写头/传动臂等机械结构摔坏。
机械硬盘容量很大(目前广泛1T,2T),咱们的数据和程序是存储在磁盘上的,因此CPU要想执行指令/数据,就要从存储器,也就是磁盘上读取, CPU一秒钟能够执行几亿条指令,可是相对之下,磁盘的读写速度就是慢如蜗牛。假设磁盘一秒钟能够读取100条指令。那么这中间就存在 巨大的速度差别。半导体行业发展了几十年,CPU的执行速度一再飞速提高,奈何磁盘技术发展的太不给力了,CPU再快,但是磁盘严重拖后腿,那CPU就至关于工做严重不饱和,若是直接从磁盘上 来读取数据,那么CPU至关于 99.9999%的时间都在闲置着。
"假设磁盘一秒钟能够读取100条指令。":带有假设字样的,具体数字都是随便写的。好比 磁盘读写速度天然有它的参数指标,不过咱们只是为了说明问题, 因此能理解其中的道理就好。
磁盘厂商们也在努力研究,好比SSD(固态硬盘),它的速度就比 机械硬盘快了一二十倍吧。可是对于CPU的速度,这也是然并卵啊。(更况且SSD相比机械硬盘太贵了)
因此这就是个大问题。
这就像是老板对咱们这些员工的但愿同样。老板给咱们发工资, 那么他就是但愿咱们每一天的每一分每一秒都在努力帮公司干活。不要有什么任什么时候间闲着。因此咱们要感谢劳动法,让咱们天天工做八小时就够了。毕竟咱们也是血肉之躯,也须要吃喝拉撒睡觉。
看到劳动法说天天工做八小时就够了,程序猿们哭晕在厕所。
程序猿问科比:“你为何这么成功? ”
科比:“你知道洛杉矶凌晨四点是什么样子吗? ”
程序猿:“不知道,通常那个时候我还没下班呢,怎么了?”
科比:“额…….”
经过上面的介绍,咱们就明白了计算机体系的主要矛盾,CPU太快了,而磁盘太慢了。因此它俩是不可以直接通讯的,咱们能够加一层过分。这就是内存的做用。这就是几百块钱一根的内存条的做用和功能。
实际上,通常状况下,内存的读写速度比磁盘快几十万倍左右。因此它终于够资格和CPU直接通讯了。
这里有张图,咱们来看一下磁盘/内存,与CPU速度之间逐渐增大的差距(主要是CPU技术发展太迅猛了)。
图三:磁盘DRAM和cpu速度之间逐渐增大的差距
因此如今程序执行过程是这样的。CPU执行任务时,只与内存通讯,它从内存获取指令/数据或写回数据。内存再与磁盘通讯,内存从磁盘读取数据/指令,或者内存将数据写回磁盘。
提到添加过渡层。这其实和JVM的原理都是相似的。具体可参考个人另外一篇文章关于跨平台的一些认识。也许这就是大道至简吧。
咱们这里说的内存,主要是指主存。就是主板上插的内存条。它的读写速度比磁盘快了几十万倍。可是相对于CPU的速度依旧仍是慢。那么主存和CPU之间,能够继续添加速度更快的过分层。因此intel i7的存储器层次结构是这样的。
图4:一个存储器层次结构的示例
前面扯了那么多篇幅,就是告诉你,咱们为何须要内存(主存),那么理解了主存,天然也就理解了L3,L2,L1等各级缓存存在的意义。对于现代的计算机系统,在CPU与磁盘/主存之间,加了多层过分层。
严格来说,应该叫CPU的算术逻辑单元(ALU),可是简单的直接说CPU,你们确定也能听得懂。
实际上这是一种缓存思想。好比,本地磁盘也至关于 远方服务器的缓存。由于咱们从网上下载数据/文件时,速度明显比从本地磁盘读取要慢。
通常状况下,L5磁盘与L4主存速度相差几十万倍, 而L3-L0之间,它们每级缓存的速度差别大概是10倍。
咱们是拿i7处理器来作例子,它有三级缓存,像低端一些的处理器,好比i3,只有两级缓存,可是道理是相同的。本文当中,都是拿i7的存储器层次来作例子。
明白一点。CPU执行速度实在太快了,一秒钟执行几亿/十几亿条指令,CPU干活干脆利落,那么存储器就要千方百计的用最快的速度把指令/数据 送给CPU去运行。不然CPU干活再快,又有什么意义呢。
基本思想已经理解了。那么咱们就开始具体讨论细节问题。
看看上面那幅图,什么SRAM,DRAM,还有咱们前面讲的SSD,Flash,机械硬盘等,还有下面要讨论的总线(BUS),因此咱们先来讨论一些基础硬件知识.
首先,他们都属于存储器,存储器分为两类:
ROM相比于RAM,容量更大,价格便宜,读写速度则比较慢。
其实我觉的把 Flash,ROM等都叫作磁盘,也没什么错。毕竟它们的做用和概念都是类似的,区别只是他们各自使用的半导体技术不一样。Flash芯片等基于集成芯片的存储器读写速度比机械硬盘快,不过(相同容量下)价格也比后者贵。而它们相比于SRAM,DRAM则很是慢了,因此后者理解为内存便可。
"图4:一个存储器层次结构的示例",越往上,读写速度越快,价格更贵,存储容量也越小。(淘宝上搜搜8G的内存条,256G的SSD,1T的机械硬盘都是什么价格就明白了)。像L0 寄存器,每一个寄存器只能存储一个字长的内容,可是CPU读写取寄存器耗费的时钟周期为0个。这是最快的速度。
另外,咱们在电脑主板上能够看到内存条(L4主存)。硬盘(L5),可是却没看到L3-L0。缘由很简单,他们都是集成在CPU芯片内部的。
咱们知道了存储器的层级结构,下面还有一个问题,就是怎么把硬盘,内存条之类的链接起来进行通讯呢,这就是 总线(Bus)了。
图6:一个典型系统的硬件组成
上图存在三条总线,IO总线,存储器总线(一般称为内存总线),系统总线。在主板上,就是那一排排的32/64根并行的导线。这些导线用来链接CPU,内存,硬盘,以其余外围设备。CPU与存储器,输入输出设备等通讯,都是经过总线。不一样总线的速度也有差别。
CPU要经过I/O桥(就是主板的北桥/南桥芯片组)与外围设备链接,由于CPU的主频过高了,它的时钟周期一秒钟震荡几亿次,外围设备的时钟周期都较慢,因此他们不能直接通讯。
本文是讨论软件的,因此硬件部分就一笔带过,读者知道有这回事就ok了。总线上携带地址,数据和控制信号, 如何区分不一样信号,分辨它与哪一个外围设备通讯,这就是另一个问题了。
有些读者脑子转的比较快,可能想到了这样一个问题。
无论你中间怎么加缓存,也无论中间的什么SRAM,DRAM的读写速度有多快,可是磁盘的读写速度就是那么慢,因此磁盘与主存之间的交互速度很慢。CPU归根到底须要向磁盘读写数据。整个环节速度瓶颈就是在磁盘那里,这个根本快不了,那么加那么多级缓存,意义有何在呢?
这是一个好问题啊。 下面让咱们继续讨论。
咱们来看看,CPU如何读取磁盘中的一个数据。
图7:读一个磁盘扇区
网上找的图片不是很清楚,注意每张图中的黑线。步骤分三部:
- CPU 将相关的命令和地址,经过系统总线和IO总线传递给磁盘,发起一个磁盘读。
- 磁盘控制器将相关的地址解析,并经过IO总线与内存总线将数据传给内存。
- 第2步完成以后,磁盘控制器向CPU发送一个中断信号。(学电子的同窗应该很清楚中断是什么)。这时CPU就知道了,数据已经发送到内存了。
第二步磁盘操做很慢,可是在第一步CPU发出信号后。可是第二步和第三部时,CPU根本不参与。第二步很耗时,因此CPU在第一步发出信号后,就去在干其余事情啊。(切换到另外一个线程)。因此此时的CPU依旧没有闲着。而待第三步时,经过中断,硬盘主动发信号给CPU,你须要的数据已经发送到内存了,而后此时它能够将线程再切换回来,接着执行这个该线程的任务。
除了多线程切换,避免CPU闲置浪费,还有一点。
我先问一个问题。
//@author :www.yaoxiaowen.com int main(){ //咱们执行任务的代码 return 0; }
对于一个应用/进程而言,它都应该有一个入口。(虽然不必定须要咱们直接写main
函数)。入口函数内部就是咱们的任务代码,任务代码执行完了这个应用/进程也就结束了。这个很好理解,好比测试工程师写的一个测试case。跑完了这个任务就结束了。
可是 有些程序,好比一个 app,你打开了这个app。不作任何操做。这个界面会一直存在,也不会消失。思考一下这是为何。由于这个app进程确定也要有一个main入口。 main里面的任务代码执行完了,就应该结束了。而一个程序的代码/指令数目确定是有限的。但该app在咱们不主动退出状况下,却不会主动结束。
因此这个app进程的入口main来说,实际上是这样的。
//@author :www.yaoxiaowen.com int main(){ boolean flag = true; while (flag){ //咱们执行任务的代码 } return 0; }
而且不只如此,在一个程序内部,也有大量的for,while等循环语句。
那么当咱们把这些相关的代码指令送到了主存,或者更高一级的缓存时,那么CPU在执行这些指令时,存取速度天然快了不少。
在执行一个程序时,启动阶段比较慢,由于须要从磁盘读取数据。(而CPU在这个阶段也没闲置浪费,它会进行线程切换执行其余任务)。 可是数据被送往内存以后,它执行起来就会快多了,而且伴随着执行过程,还可能愈来愈快,由于这些数据,有可能被一级一级的向上送,从L4,送到L3,再送到L2,L1
so,上述那个问题的答案,已经解释的比较清楚了吧。
locality对于硬件和软件系统的设计和性能都有着重要的影响。对于咱们理解存储器的层次结构也必不可缺。
程序倾向于引用临近于与其余最近引用过的数据项的数据项。或者最近引用过的数据项自己。这种倾向性,咱们称之为局部性原理。它一般有如下两种形式:
- 时间局部性(temporal locality):被引用过一次的存储器位置的内容在将来会被屡次引用。
- 空间局部性(spatial locality):若是一个存储器位置的内容被引用,那么它附近的位置也很大几率会被引用。
通常而言,有良好局部性的程序比局部性差的程序运行的更快。 现代计算机系统的各个层次,从硬件到操做系统、再到应用程序,它们的设计都利用了局部性。
固然,光说理论的东西比较玄乎。咱们来看实际的例子。
//@author www.yaoxiaowen.com int sum1(int array[N]) { int i, sum = 0; for(i = 0; i < N; i++) sum += array[i]; return sum; }
在这个程序中,变量sum
,i
在每次循环迭代时被引用一次,所以对sum
和i
来讲,有较好的时间局部性。
对变量array
来讲,它是一个int类型数组,循环时按顺序访问array
,由于一个C数组在内存中是占用连续的内存空间。于是的较好的空间局部性,
再来看一个例子:
//@author www.yaoxiaowen.com int sum2(int array[M][N]) { int i, j, sum = 0; for(i = 0; i < M; i++){ for(j = 0; j < N; j++) sum += array[j][i]; } return sum; }
这是一个空间局部性不好的程序。
假设这个数组是array[3][4]
,由于C数组在内存中是按行顺序来存放的。因此sum2对每一个数组元素的访问顺序成了这样:0, 4, 8, 1, 5, 9…… 7, 11。因此它的空间局部性不好。
可是幸运的是,通常状况下软件编程自然就是符合局部性原理的。好比程序的循环结构。
假设CPU须要读取一个值,int var
,而var
在L4主存上,那么该值会被依次向上送,L4->L3->L2,可是这个传递的过程并非单纯的只传递var
四个字节的内容,而是把var
所在的内存块(block),依次向上传递,为何要传递block?由于根据局部性原理,咱们认为,与var
值相邻的值,将来也会被引用。
存储器的层次结构,数据进行传送时,是以block(块)为单位传送的。在整个层次结构上,越往上,block越小而已。
洋洋洒洒的扯了那么多,我相对于所谓的 存储器层次结构读者应该有一个基本的认识,有些地方介绍的 不够严谨,可是本文的目的也就是让你们理解基本思想。
归根到底,它就是一个缓存(caching)的思想,而且其实不复杂,
咱们作app开发时,对于app中活动页面等,都是后台发给咱们图片url,咱们下载后才显示在app上,这时咱们总要使用
Glide
,Picasso
等图片缓存框架来把下载好的图片缓存在手机本地存储上。这样下次打开app时,若是这个图片连接没有改变,咱们就直接拿手机本地缓存的图片来进行显示,而不用再从服务器上下载了。若是图片连接改变了,则从新下载。为何要这么作?由于从服务器上下载比较慢,而手机本地存储(ROM)中读取就会快不少。
这个时候能够再回头看看"图4:一个存储器层次结构的示例"。
下面这张图和这段文字来自《深刻理解计算机系统》(CSAPP),你们能够有个更严谨和细节的认识。
图8:存储器层次结构中基本的缓存原理
存储器层次结构的中心思想:位于k层的更快更小的存储设备做为位于k+1层得更大更慢的存储设备的缓存;数据老是以块大小为传送单元(transfer unit)在第k层和第k+1层之间来回拷贝的;任何一对相邻的层次之间传送的块大小是固定的,即每一级缓存的块大小是固定的。可是其它的层次对之间能够有不一样的块大小。
当程序须要第k+1层的某个数据对象d时,它首先在当前存储在第k层的一个块中查找d。若是d恰好在k层,那么就是缓存命中。若是第k层中没有缓存数据对象d,那么就是缓存命不中。当缓存不命中发生时,第k层的缓存从第k+1层 缓存中取出包含d的那个块,若是第k层的缓存已经满了的话,可能会覆盖现存的一个块。(覆盖策略可使用常见的LRU算法)。
volatile
关键字在java和C当中,有一个volatile
关键字(其余语言估计也有),它的做用就是在多线程时保证变量的内存可见性,可是具体怎么理解呢?
咱们在"图4:一个存储器层次结构的示例"中,说的缓存结构其实对于一个单核CPU而言的,好比 对于 一个四核三级缓存的CPU,它的缓存结构是这样的。
图9:多核处理器缓存结构
咱们能够看到L3
是四个核共有的,可是L2
,L1
实际上是每一个核私有的,若是我有一个变量var
,它会被两个线程同时读取,这两个线程在两个核上并行执行,由于咱们的缓存原理,这个var
可能分别在两个核的 L2
或L1
缓存,这样读取速度最快,可是该var
值可能就分别被这两个核分别修改为不一样的值, 最后将值回写到L3
或L4
主存,此时就会发生bug了。
因此volatile
关键字就是预防这种状况,对于被volatile
修饰的的变量,每次CPU须要读取时,都至少要从L3
读取,而且CPU计算结束后,也马上回写到L3
中,这样读写速度虽然减慢了一些,可是避免了该值在每一个core的私有缓存中单独操做而其余核不知道。
本篇是"什么是内存"系列第一篇文章,下一篇文章会讨论关于内存的另外一个重要方面,两篇文章加起来,相信你们会对内存有一个全面的,全新的认识。
这里请你们思考如下几个问题。
- 无论什么程序,最后的直接/间接的编译结果都是0和1,(咱们直接理解为汇编)。(这点不知道的,欢迎阅读个人另外一篇文章关于跨平台的一些认识),好比这句汇编代码:
mov eax,0x123456;
它的意思是将内存0x123456
处的内容送往eax
这个寄存器。各个应用的数据共同存在内存中的。假设有一个音乐播放器应用的汇编代码中,引用了0x123456
这个内存地址。可是同时运行的应用有不少,那其余应用也彻底有可能引用0x123456
这个地址。那为何居然没起冲突和错误呢?
- 进程是计算机领域最重要的概念之一,什么是进程?进程是关于某次数据集合的一次运行活动, 是运行在它本身地址空间的一段自包容程序, 解释的通俗的点, 一个程序在运行时,咱们会获得一个假象,该进程好像是独占地使用CPU和内存,CPU是没有间断地一条接一条的执行该程序的指令,全部的内存空间都是供该进程的代码和数据分配使用的。(这点不严谨,其实内存还有一部分要分给
内核kernel
)。提及来,这个程序就好像获得了全世界同样。,CPU是个人,内存也所有个人,妹子们仍是个人。固然这是假象而已。可是这些假象又是怎么作到的呢?
- 程序中都会引用库API,好比每一个C程序都要引用
stdio.h
库的printf()
,在程序运行时,库代码也要被加入到内存,这么多程序都引用了这个库,难道我内存中须要加不少份吗?这天然不可能,那么库代码又是怎么被全部进程共享的呢?
下篇文章将会给你们解释这些问题,而且这些问题的答案是很是简单的。相信你们看了会有恍然大悟的感受,敬请期待。
1109补充
什么是内存(二):虚拟内存已经发表。欢迎指点批评。
博客地址: www.cnblogs.com/yaoxiaowen/
github: https://github.com/yaowen369
欢迎对于本人的博客内容批评指点,若是问题,可评论或邮件(yaowen369@gmail.com)联系
欢迎转载,转载请注明出处.谢谢