操作系统之内存的基础知识

操作系统之内存的基础知识

一、什么是内存,有何作用

内存是用于存放数据的硬件。程序执行前需要先放到内存中才能被CPU处理。

那么,为什么必须将程序和数据先放到内存中才能被CPU处理呢?因为,CPU是计算速度极快的硬件,而外存中数据读取速度慢,这会导致CPU的极快处理速度无法发挥,而内存的读取速度很快,就能够满足CPU的计算速度要求,使得CPU这个昂贵的硬件功能得到充分的发挥。

简单来说,CPU这个硬件太高级了看不起外存这个伙伴,而只有内存这个家伙才配得上和CPU合作。


理解了内存后,我们再思考一个问题:在多道程序环境下,系统中会有多个程序并发执行,也就是说会有多个程序的数据需要同时放到内存中。那么,如何区分各个程序的数据是放在什么地方的呢?

这个问题的解决方案就是将内存分隔为一个个的存储单元,并且为存储单元进行编地址,这样就能将每个程序存储在某些存储单元中,并通过地址寻找到这些程序。

内存编址类似我们平常的酒店,把酒店当做一整块内存,那么每个房间就是一个存储单元。每个存储单元对应一个地址,每个存储单元的大小根据计算机的编址方式各不相同,如果采用按字节编址,这每个存储单元大小为1字节,即1B,即8个二进制位;如果字长为16位的计算机按字编址,则每个存储单元大小为1个字;每个字的大小为16个二进制位。
在这里插入图片描述

二、进程运行的基本原理

1. 指令

指令:CPU能够识别的命令。
因此,我们写的代码首先要翻译成CPU能识别的指令。这些指令会告诉CPU应该去内存的哪个地址存/取数据,这个数据应该做什么样的处理。
如x=x+1经过编译后有3条指令组成,每条指令的第一个二进制数称为“操作码:
指令1 (00101100, 00000011,01001111)数据传送指令:将内存地址01001111的数据传送到地址为00000011的寄存器中
指令2(10010010,00000011, 00000001) 加法指令:将地址00000011的寄存器中的数据加1
指令3(00101100,01001111, 00000011)数据传送指令:将地址00000011的寄存器中的数据传送到存放变量x的地址
在这里插入图片描述
在这个例子中,指令中直接给出了变量x的实际存放地址(物理地址)。但实际在生成机器指令的时候并不知道该进程的数据会被放到什么位置。所以编译生成的指令中一般是使用逻辑地址(相对地址)

2. 逻辑地址vs物理地址

我们还以酒店进行举例,假设酒店是一块内存,而每个房间是一个存储单元,每个存储单元都有一个地址,这个地址就是物理地址,即实实在在的内存中的地址;

而现在酒店门口站了三个学生,他们的编号依次0,1,2,他们要求按照编号递增次序入住房间,因为他们还没真正入住到酒店,那么现在的编号就是相对位置,也就是内存中的逻辑地址。

那么一旦确定了编号为0的学生入住5号房间,那么其余两名学生的房间也就确定了,分别是6号房和7号房,即一旦确定逻辑地址中的一个的物理地址,那么其它逻辑地址的物理地址就可以得到。

指令中的地址也可以采用这种思想。编译时产生的指令只关心“相对地址”,实际放入内存中时再想办法根据起始位置得到“绝对地址”。

3. 从写程序到程序运行的过程

从前面的学习我们知道,程序运行之前必须先把程序和数据加载到内存,而这之前需要经过以下步骤:

  1. 编辑:也就是我们程序员撸代码,形成源代码
  2. 编译:由编译程序将源代码编译成若干个目标模块(编译就是把高级语言翻译为机器语言)
  3. 链接:由链接程序将编译后形成的一组目标模块,以及所需库函数链接在一起,形成一个完整的装入模块
  4. 装入:由装入程序将装入模块装入内存指定的位置(物理地址)。
    在这里插入图片描述
    由上图可知,装入过程要先完成逻辑地址到物理地址的转换,然后将程序和数据装入内存中指定的物理地址。根据逻辑地址到物理地址所采用的不同转换方法将装入分为三种方式,下面详细讲解这三种装入方式(逻辑地址转物理地址方式)

4. 装入的三种方式

4.1 绝对装入

这是最简单的方式,即不需要经过逻辑地址到物理地址的转换,因为指令的地址一直都是物理地址。

即在编译时,就已经知道程序将放到内存中的哪个位置,编译程序直接产生绝对地址(物理地址)的目标代码。装入程序按照装入模块中的地址,直接将程序和数据装入内存即可。
在这里插入图片描述


特点:
因为这种方式需要在编译时就知道程序放在内存中的哪个位置,因此,这种方式只适用于单道程序环境,因为单道程序保证只有一个程序在访问内存,不会导致不同程序相互竞争占用同一块内存的情况。


4.2 静态重定位

静态重定位:又称可重定位装入。编译、链接后的装入模块的地址都是从0开始的,指令中使用的地址、数据存放的地址都是相对于起始地址而言的逻辑地址。可根据内存的当前情况,将装入模块装入到内存的适当位置。装入时对地址进行“重定位”,将逻辑地址变换为物理地址(地址变换是在装入时一次完成的)。

简而言之,这种方式就是在装入之前就必须分配其需要的全部内存空间,并且确定内存的起始位置,然后一次性完成所有指令的逻辑地址到物理地址的转换。
在这里插入图片描述


特点:
静态重定位的特点是在一个作业装入内存时,必须分配其要求的全部内存空间,如果没有足够的内存,就不能装入该作业。作业一旦进入内存后,在运行期间就不能再移动,也不能再申请内存空间。


4.3 动态重定位

动态重定位:又称动态运行时装入。编译、链接后的装入模块的地址都是从0开始的。装入程序把装入模块装入内存后,并不会立即把逻辑地址转换为物理地址,而是把地址转换推迟到程序真正要执行时才进行。因此装入内存后所有的地址依然是逻辑地址。这种方式需要一个重定位寄存器的支持。

简而言之,这种方式就是在将逻辑地址转为物理地址推迟到了具体的程序运行时期,即当运行到该指令再实时执行逻辑地址到物理地址的转换,具体是通过一个重定位寄存器实现的。重定位寄存器中存放了装入模块在内存中的起始地址,我们只需要将逻辑地址与寄存器中的起始地址相加就可以得到实际的物理地址。

如下图是指令1是向逻辑地址为80的位置的存储单元写入1,然后寄存器中存储的起始位置为100,那么对应的物理地址是100+80=180,即指令1实际会向地址为180的位置写入数字1.
在这里插入图片描述


特点:

  1. 采用动态重定位时允许程序在内存中发生移动(只需要对应修改重定位寄存器中的起始位置就可以了)
  2. 可将程序分配到不连续的存储区中;在程序运行前只需装入它的部分代码即可投入运行,然后在程序运行期间,根据需要动态申请分配内存;便于程序段的共享,可以向用户提供一个比存储空间大得多的地址空间。

4.4 总结

绝对装入和静态重定位装入的方式,都是一次性将程序全部装入到指定内存位置,并且后续程序位置不能发生改变;
而动态重定位装入方式是可以一部分一部分的装入内存,并且程序在内存中的位置并不固定,可以发生移动(只需要对应修改重定位寄存器中的起始位置就可以了)

5. 链接的三种方式

链接是将编译为CPU可以识别的多个机器代码目标模块整合为一个完整的装入模块。根据链接的时期将其分为三种方式。

更简单的理解链接就是比如你在自己的代码中调用一个已有Math库中的max函数求最大值, 那么你的代码就依赖于Math库,因此,就需要把你的程序和Math库中的程序链接(整合)到一起才能让你的程序顺利执行下去。

5.1 静态链接

在程序运行之前,先将各目标模块及它们所需的库函数连接成一个完整的可执行文件(装入模块),之后不再拆开。
在这里插入图片描述

5.2 装入时动态链接

将各目标模块装入内存时,边装入边链接的链接方式(一次性依次将所有模块装入)
在这里插入图片描述

5.3 运行时动态链接

在程序执行中需要该目标模块时,才对它进行链接。其优点是便于修改和更新,便于实现对目标模块的共享。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mekeater

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值