一、程序装载的挑战
在运行可执行文件的时候、装载器会把对应的指令和数据加载到内存中、让CPU执行、装载器需要满足两个条件:
- 可执行程序加载后占用的空间是连续的、
- 需要同时加载多个程序、并且不能让程序自己规定在内存中加载的位置
因为想要的地址可能已经被其它程序给占了
解决:
在内存里找到连续内存空间分配给装载的程序、然后把这段连续的内存地址和整个程序指令里的指定内存地址做映射
虚拟内存地址
Virtual Memory Address
指令里用到的地址物理内存地址
Physical Memory Address
在内存硬件里的地址
程序中有指令和各种内存地址、我们只需要关心虚拟内存地址就行了、对于任何一个程序来说、它看到的都是同样的内存地址、我们维护一个虚拟内存到物理内存的映射表、这样实际程序指令执行时、会通过虚拟内存地址、找到对应的物理内存地址、然后执行.
因为地址是连续的、只需要维护映射关系的起始地址和对应的空间大小就可以了
二、内存分段分段
找出一段连续的物理内存和虚拟内存地址进行映射的方法
分段解决了程序本身不需要关心具体内存地址的问题、也有一些不足之处、内存碎片
内存交换
Memory Swapping
将程序写回硬盘、再从硬盘读回、读回时放到连续空间位置上、这样剩余空间就是连续的了、解决了内存碎片
的问题
但: 若内存交换的时候交互的是一个内存占用很大的程序、机器会十分卡顿
三、内存分页
既然问题出在内存碎片和交换空间太大上、那么解决办法就是: 少程序内存碎片、另外 当进行内存交换的时候、让需要交换的数据更少、那么问题就可以解决
这个办法在计算机的内存管理里边叫内存分页
内存分页
是把整个物理内存空间切成一段固定尺寸的大小、这样一个连续并且尺寸固定的内存空间叫页(Page)
1 | getconf PAGE_SIZE # 查看页大小、默认4k |
由于内存是预先划分好的、就没有了不能使用的碎片、只有被释放出来的很多4kb的页、即使内存空间不够、需要让现有的正在运行的程序通过内存交互、释放出来一些内存空间、一次写入磁盘的也只有少数一个或者几个页、不会花很多时间、不会卡顿
进一步、程序加载的时候不是一次性全部加载、二手在运行时、需要用到对应虚拟内存页里的指令和数据时才加载、读取特定页时、发现数据未加载到物理内存时会触发一个来自CPU的缺页错误(Page Fault) 系统捕获这个错误、将对应页从虚拟内存读取加载到物理内存
四、链接: 动态链接和静态链接动态链接
Dynamic Link
链接的不是存储在硬盘上的目标文件代码、二手加载到内存的共享库
(shared Libiaries
)静态链接
之前说到的合并代码段的方式
在win下、共享库文件是.dll
文件、也就是 Dynamic-Link Library
(DLL, 动态链接库).
在Linux下、就是.so
文件、(Shared Object
)
五、电信号&门电路
远古传信: 人工、速度慢
-> 金、鼓: 距离有限
-> 烽火台: 光信号、不能传递复杂信息
-> 电报: 传输距离增加、输入信号速度加快
-> 继电器: 解决更远距离传输