学习日期:2024.6.17
内容摘要:内存和进程运行的基本原理
存储单元与地址
程序执行之前要先放在内存里,系统中会有多个程序并发执行(所以会有多个程序同时放进内存里),为了区分,就会给内存的存储单元编地址,存储单元好比酒店的房间,每个地址好比一个房间的门牌号,一个手机有4G内存,意思就是这个“酒店”能存储4*2^30个字节,有这么多个房间
内存地址从0开始,每个地址对应一个存储单元
若计算机“按字节编址”,则每个存储单元大小为一个字节,即1B,八个二进制位
若“按字编址”,则每个存储单元大小为一个字,看计算机的字长,例如计算机字长为16,那就是16个二进制位
指令的工作原理
拿x=x+1为例
程序先编译(build&run的build),编译为以下三条机器指令(指令编码随便写的,仅帮助理解)
指令1(01000011,00000011,01001111)数据传送指令
指令2(10010010,00000011,00000001)加法指令
指令3(01000011,01001111,00000011)数据传送指令
CPU首先读指令1,红色的部分叫操作码,CPU读到这个就知道“嗷,我要传送数据了”,那要传什么呢,再看后面的,我要把编号79(01001111)的内存单元的数据取到编号为3(00000011)的这个寄存器里面
之后再看指令2,CPU看到操作码了, 就知道要做加法了,再看后面的,要把寄存器3里的内容加上1(00000001)
指令3和指令1同理,把运算完的结果再传回x这个变量原来的地址(3传回79),这样就完成了x=x+1这个操作
显然,CPU在执行指令的过程中,就是在处理内存/寄存器中的数据,而找到这些数据离不开“地址”,就是离不开它们的门牌号
在这个例子当中,我们默认了地址是从#0开始连续保存的,显然,实际生活中不可能保证我们每个进程都从0开始,那么该怎么办呢?
逻辑地址
为了解决这个问题,我们引入逻辑地址这一概念
还是拿刚刚那个程序举例子,现在我们定义int x=10,在编译完成后,形成了一个.exe文件,我们程序生成的指令中指明的地址是“逻辑地址”,即相对于进程的起始地址而言的地址
进程是分为程序段和数据段的,我们读数据的地址都是读的数据段
拿酒店房间来说,就是我们这个进程的指令的起始门牌号定义为0,指令中的地址都是以这个定义为0的地址上加的地址
画个表格便于理解
指令 | 物理地址 | 逻辑地址 |
...(别的进程) | 0 | ... |
... | 1 | ... |
... | ... | ... |
指令0:往地址为79的存储单元里写入10 | 100 | 0 |
指令1:把地址79中的数据读入编号为3的寄存器 | 101 | 1 |
指令2:把寄存器3中的数据+1 | 102 | 2 |
指令3:xxx | 103 | 3 |
... | ... | ... |
此时,我们的指令0,地址79指的是逻辑地址,即物理地址为179的存储单元,x的值就放在这
那么,如何将指令中的逻辑地址转换为物理地址呢?
有绝对装入,可重定位装入,动态运行时装入三个办法
一、绝对装入
在编译时,如果知道程序将放到内存中的哪个位置,就把绝对地址的目标代码直接装入模块中的地址。还是刚刚的例子,在编译的时候,得到的装入模块的指令直接使用绝对地址
即指令0是:往地址为179的存储单元中写入10 指令1:把地址179中的数据读入编号为3的寄存器
绝对装入需要知道装入模块会装到内存的具体位置,灵活性很差(换一个电脑,内存的物理地址就变了,不再适用),只适用于单道程序环境。
二、可重定位装入(静态重定位)
在编译时,把起始地址记下来,然后逻辑地址在起始地址的基础上“重定位”。如上例来说,起始物理地址是100,那就把指令中的每个逻辑地址+100,找到其对应的物理地址(地址变换在装入时一次完成)
缺点:作业一旦进入内存,在运行期间就不能再移动,也不能申请内存空间
三、动态运行时装入(动态重定位)
编译后使用的是逻辑地址,程序装入内存时依然使用逻辑地址。
系统设置专门的重定位寄存器,专门存放装入模块存放的起始位置,CPU在访问起始地址时,会加上重定位寄存器里面的值,以此来达到定位的目的
从写程序到程序运行
程序员写好代码文件main(),a(),b()
编译程序将代码编译成若干个目标模块(编译就是将高级语言翻译为机器语言)
链接程序将编译形成后的一组目标模块链接在一起,形成完整的装入模块
装入:由装入程序将装入模块 装入内存中运行
链接的三种方式:
静态链接:先链接成完整的可执行文件,再一次装入
装入时动态链接:边装入边链接
运行时动态链接:程序执行时需要该目标模块时,才将其装入
操作系统的管理范畴
1.内存空间的分配与回收
2.从逻辑上对内存空间扩充(虚拟内存)
3.地址转换功能,将程序的逻辑地址和物理地址转换(三种装入方式)
4.内存保护功能,保证各个进程在各自存储空间内运行,互不干扰
内存保护的方法:
上下限寄存器,存放进程上下限地址,进程的指令要访问时,CPU检查是否越界
重定位寄存器和界地址寄存器(存放起始物理地址和最大逻辑地址)