赞
踩
4 人赞同了该文章
最直观的,我们买手机,电脑,内存条,都会标明内存是多大,例如途中的8G,16G,128G都指的内存大小,另外支持国货,支持华为。
我们应该都听说过 RAM 存储器,它是一种半导体存储器件。RAM 是英文单词 Random 的缩写,即“随机”的意思。所以 RAM 存储器也称为“随机存储器”。
那么 RAM 存储器和内存有什么关系呢?内存就是许多 RAM 存储器的集合,就是将许多 RAM 存储器集成在一起的电路板。RAM 存储器的优点是存取速度快、读写方便,所以内存的速度当然也就快了。
有何作用?
稍微了解操作系统历史的人,都知道没有操作系统的裸机->一次只能运行一个程序的单道批处理系统->多道批处理系统->分时系统这个发展历程。
主要是人工操作,程序员将对应用程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把程序和数据输入计算机内存,接着通过控制台开关启动程序针对数据运行;计算完毕,打印机输出计算结果;用户取走结果并卸下纸带(或卡片)后,才让下一个用户上机。
人机矛盾:手工操作的慢速度和计算机的高速度之间形成了尖锐矛盾,手工操作方式已严重损害了系统资源的利用率(使资源利用率降为百分之几,甚至更低),不能容忍。唯一的解决办法:只有摆脱人的手工操作,实现作业的自动过渡。这样就出现了成批处理。
特点是一次只能运行一个进程,只有运行完毕后才能将下一个进程加载到内存里面,所以进程的数据都是直接放在物理内存上的,因此CPU是直接操作内存的物理地址,这个时候不存在虚拟逻辑地址,因为一次只能运行一个程序。
矛盾:每次主机内存中仅存放一道作业,每当它运行期间发出输入/输出(I/O)请求后,高速的CPU便处于等待低速的I/O完成状态,致使CPU空闲。
到后来发展出了多道程序系统,它要求在计算机中存在着多个进程,处理器需要在多个进程间进行切换,当一道程序因I/O请求而暂停运行时,CPU便立即转去运行另一道程序。
问题来了,这么多进程,内存不够用怎么办,各个进程同时运行时内存地址互相覆盖怎么办?
这时候就出现问题了,链接器在链接一个可执行文件的时候,总是默认程序的起始地址为0x0,但物理内存上只有一个0x0的地址呀?也许你会说:”没关系,我们可以在程序装入内存的时候再次动态改变它的地址.”好吧我忍了。但如果我的物理内存大小只有1G,而现在某一个程序需要超过1G的空间怎么办呢?你还能用刚才那句话解释吗?
操作系统的发展,包括后面的分时系统,其实都是在解决协调各个环节速度不匹配的矛盾。
存储器层次之间的作用和关联为金字塔形状,CPU不可以直接操控磁盘,是通过操控内存来进行工作的,因为磁盘的速度远远小于CPU的速度,跟不上,需要中间的内存层进行缓冲。
内存速度比硬盘速度快的原理: 内存的速度之所以比硬盘的速度快(不是快一点,而是快很多),是因为它们的存储原理和读取方式不一样。
内存通过电存取数据,本质上就是因为 RAM 存储器是通过电存储数据的。但也正因为它们是通过电存储数据的,所以一旦断电数据就都丢失了。因此内存只是供数据暂时逗留的空间,而硬盘是永久的,断电后数据也不会消失。
小结:程序执行前需要先放到内存中才能被CPU处理,因此内存的主要作用就是缓和CPU与硬盘之间的速度矛盾。
相关视频推荐
90分钟了解Linux内存架构,numa的优势,slab的实现,vmalloc的原理
linux内存管理问题-如何理出自己的思路出来,开发与面试双丰收
需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
在多道程序环境下,系统中会有多个程序并发执行,也就是说会有多个程序的数据需要同时放到内存中。那么,如何区分各个程序的数据是放在什么地方的呢?
方案: 给内存的存储单元编地址。
程序运行过程如下:
编译: 把高级语言翻译为机器语言;
链接: 由链接程序将编译后形成的一组目标模块,以及所需库函数链接在一起,形成一个完整的装入模块;
装入(装载): 由装入程序将装入模块装入内存运行;
可以看到运行时动态链接,不需要一次性将模块全部装入内存,可以等到运行时需要的时候再动态的连接进去,这样一来就就提供了内存不够用的问题的解决思路,还可以这样,用到了再链接进去。
1.绝对装入
编译或汇编时得到绝对地址,即内存物理地址,直接存到对应的物理地址。
单道处理系统就是直接操作物理地址,因此绝对装入只适用于单道程序环境。
又称可重定位装入,这里引入逻辑地址,装入时将逻辑地址重定位转化为物理地址,多道批处理系统的使用方式。
静态重定位的特点是在一个作业装入内存时,必须分配其要求的全部内存空间,如果没有足够的内存,就不能装入该作业。作业一旦进入内存后,在运行期间就不能再移动,也不能再申请内存空间。
又称动态运行时装入,运行时将逻辑地址重定位转化为物理地址,这种方式需要一个重定位寄存器的支持,当然现代操作系统使用的都是这种。
逻辑地址都是从0开始的,假设装入的起始物理地址为100,动态重定位装入如下图:
在单一连续分配方式中,内存被分为系统区和用户区。系统区通常位于内存的低地址部分,用于存放操作系统相关数据;用户区用于存放用户进程相关数据。内存中只能有一道用户程序,用户程序独占整个用户区空间。
优点:实现简单;无外部碎片;
缺点:只能用于单用户、单任务的操作系统中;有内部碎片;存储器利用率极低。
将整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业,这样就形成了最早的、最简单的一种可运行多道程序的内存管理方式。
操作系统需要建立一个数据结构——分区说明表,来实现各个分区的分配与回收。每个表项对应一个分区,通常按分区大小排列。每个表项包括对应分区的 大小、起始地址、状态(是否已分配),如下图。
当某用户程序要装入内存时,由操作系统内核程序根据用户程序大小检索该表,从中找到一个能满足大小的、未分配的分区,将之分配给该程序,然后修改状态为“已分配”。
优点: 实现简单,无外部碎片。
缺点: 会产生内部碎片,内存利用率低。
动态分区分配又称为可变分区分配。这种分配方式不会预先划分内存分区,而是在进程装入内存时, 根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数 目是可变的。(eg:假设某计算机内存大小为 64MB,系统区 8MB,用户区共 56 MB...)
产生三个问题:
动态分区分配又称为可变分区分配。这种分配方式不会预先划分内存分区,而是在进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数目是可变的。
缺点:动态分区分配没有内部碎片,但是有外部碎片。
内部碎片:分配给某进程的内存区域中,有些部分没有用上。
外部碎片:是指内存中的某些空闲分区由于太小而难以利用。
如果内存中空闲空间的总和本来可以满足某进程的要求, 但由于进程需要的是一整块连续的内存空间,因此这些 “碎片”不能满足进程的需求。 可以通过紧凑(拼凑,Compaction)技术来解决外部碎片。
连续分配:为用户进程分配的必须是一个连续的内存空间。
非连续分配:为用户进程分配的可以是一些分散的内存空间。
将内存空间分为一个个大小相等的分区(比如:每个分区 4KB),每个分区就是一个“页框”(页框=页帧=内存块=物理块=物理页面)。每个页框有一个编号,即“页框号”(页框号=页帧号=内存块号=物理块号=物理页号),页框号从0开始。
将进程的逻辑地址空间也分为与页框大小相等的一个个部分,每个部分称为一个“页”或“页面” 。每个页面也有一个编号,即“页号”,页号也是从0开始。
操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。也就是说,进程的页面与内存的页框有一一对应的关系。各个页面不必连续存放,可以放到不相邻的各个页框中。
注: 进程的最后一个页面可能没有一个页框那么大。也就是 16K-1 内存,分页存储有可能产生内部碎片,因此页框不能太大,否则可能产生过大的内部碎片造成浪费。
为了能知道进程的每个页面在内存中存放的位置,操作系统要为每个进程建立一张页表,页表通常存在PCB(进程控制块)中。
页号 = 逻辑地址 / 页面长度 (取除法的整数部分)
页内偏移量 = 逻辑地址 % 页面长度(取除法的余数部分)
基本地址变换:
基本地址变换机构可以借助进程的页表将逻辑地址转换为物理地址。 通常会在系统中设置一个页表寄存器(PTR),存放页表在内存中的起始地址F 和页表长度M。 进程未执行时,页表的始址 和 页表长度 放在进程控制块(PCB)中,当进程被调度时,操作系 统内核会把它们放到页表寄存器中。
引入快表地址变换:
快表,又称联想寄存器(TLB, translation lookaside buffer ),是一种访问速度比内存快很多的高速缓存(TLB不是内存!),用来存放最近访问的页表项的副本,可以加速地址变换的速度。与此对应,内存中的页表常称为慢表。
注:TLB 和 普通 Cache 的区别——TLB 中只有页表项的副本,而普通 Cache 中可能会有其他各种数据的副本
快表快多少?
例:某系统使用基本分页存储管理,并采用了具有快表的地址变换机构。访问一次快表耗时 1us,访问一次内存耗时 100us。若快表的命中率为 90%,那么访问一个逻辑地址的平均耗时是多少?
(1+100) * 0.9 + (1+100+100) * 0.1 = 111 us 有的系统支持快表和慢表同时查找,如果是这样,平均耗时应该是 (1+100) * 0.9 + (100+100) * 0.1 = 110.9 us
若未采用快表机制,则访问一个逻辑地址需要 100+100 = 200us 显然,引入快表机制后,访问一个逻辑地址的速度快多了。
单级页表的问题:
问题一: 根据页号查询页表的方法:K 号页对应的页表项存放位置 = 页表始址 + K * 4 ,页表必须连续存放,因此当页表很大时,需要占用很多个连续的页框;
问题二:没有必要让整个页表常驻内存,因为进程在一段时间内可能只需要访问某几个特定的页面。
解决办法:把页表再分页并离散存储,然后再建立一张页表记录页表各个部分的存放位置,称为页目录表,或称外层页表,或称顶层页表。
感兴趣的看看多级页表分页方式。
进程的地址空间:按照程序自身的逻辑关系划分为若干个段,每个段都有一个段名(在低级语言 中,程序员使用段名来编程),每段从0开始编址。
内存分配规则: 以段为单位进行分配,每个段在内存中占据连续空间,但各段之间可以不相邻。
1.1 页是信息的物理单位。分页的主要目的是为了实现离散分配,提高内存利用率。分页仅仅是系统管理上的需要,完全是系统行为,对用户是不可见的。
1.2 段是信息的逻辑单位。分段的主要目的是更好地满足用户需求。一个段通常包含着一组属于一个逻辑模块的信息。
2.1 分段对用户是可见的,用户编程时需要显式地给出段名。
2.2 页的大小固定且由系统决定。段的长度却不固定,决定于用户编写的程序。
3.1 分页的用户进程地址空间是一维的,程序员只需给出一个记忆符即可表示一个地址。
3.2 分段的用户进程地址空间是二维的,程序员在标识一个地址时,既要给出段名,也要给出段内地址。
4.1 分段比分页更容易实现信息的共享和保护。 不能被修改的代码称为纯代码或可重入代码(不属于临界资源),这样的代码是可以共享的。可修改的代码是不能共享的(比如,有一个代码段中有很多变量,各进程并发地同时访问可能造成数据不一致)
与“分页”最大的区别就 是——离散分配时所分配地址空间的基本单位不同。
分段和分页的优缺点:
每个段对应一个段表项,每个段表项由段号、页表长度、页表存放块号(页表起始 地址)组成。
每个段表项长度相等,段号是隐含的。
内存每个页面对应一个页表项,每个页表项由页号、页面存放的内存块号组成。每个页表项长度相等,页号是隐含的。
很多游戏的大小超过 60GB,按理来说这个游戏程序运行之前需要把 60GB 数据全部放入内存。然而,实际我的电脑内存才 8GB,我还要开着微信浏览器等别的进程,但为什么这个游戏可以顺利运行呢?
利用虚拟技术(操作系统的虚拟性)
时间局部性: 如果执行了程序中的某条指令,那么不久后这条指令很有可能再次执行;如果某个数据被访问过,不久之后该数据很可能再次被访问。(因为程序中存在大量的循环);
空间局部性: 一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很有可能被访问。 (因为很多数据在内存中都是连续存放的,并且程序的指令也是顺序地在内存中存放的)
虚拟内存大小是多少?
虚拟内存的最大容量是由计算机的地址结构(CPU寻址范围)确定的,虚拟内存的实际容量 = min(内存和外存容量之和,CPU寻址范围)
如:某计算机地址结构为32位,按字节编址,内存大小为512MB,外存大小为2GB。
则虚拟内存的最大容量为 2^32 B = 4GB;
虚拟内存的实际容量 = min (232B, 512MB+2GB) = 2GB+512MB;
请求分页存储管理与基本分页存储管理的主要区别:
缺页中断是因为当前执行的指令想要访问的目标页面未调入内存而产生的,因此属于内中断一条指令在执行期间,可能产生多次缺页中断。(如:copy A to B,即将逻辑地址A中的数据复制到 逻辑地址B,而A、B属于不同的页面,则有可能产生两次中断)
页面的换入、换出需要磁盘 I/O,会有较大的开销,因此好的页面置换算法应该追求更少的缺页率
为了使编程更方便,程序员写程序时应该只需要关注指令、数据的逻辑地址。而逻辑地址到物理地址的转换(这个过程称为地址重定位)应该由操作系统负责,这样就保证了程序员写程序时不需要关注物理内存的实际情况。
具体的地址转化方式如上。
操作系统需要提供内存保护功能。保证各进程在各自存储空间内运行,互不干扰。
操作系统是程序员内功了,修炼好内功才能走的更远啊。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。