进程运行的基本原理
- 编译
- 编译器将代码编译成计算机识别的二进制指令。
- 链接
- 库和目标二进制模块结合链接成一个可装入模块。
- 装入
- 将可装入模块装入内存。
编译
编程语言的不同所以需要用户完成编译的动作。
链接
连接程序在程序运行之前,将编译后的二进制文件以及需要加载的库等打包成装入模块。
静态链接
程序比较小,可以一次性打包成装入模块,然后装入。
装入时动态链接
先完成一部分装入模块,然后在装入的过程中继续完成链接装入,提高运行效率。
运行时动态链接
程序比较大,先完成一部分装入模块,装入到内存中,运行过程中发现需要用到了,然后再进行链接装入内存。
装入
就是将装入模块转移到内存中,将程序的物理地址转换为逻辑地址。
- 逻辑地址:装入内存中的地址。
- 物理地址:字节文件存放的地址。
绝对装入
从0开始存放,认为内存中是空的,按0地址依次装入。
可重定位装入
多个程序装入的时候,默认也是从0开始的,但是发现地址已经被占用了,后续的程序就从空闲的内存地址往后顺延装入。
内存保护
装入的过程中,这块空间不被别的程序访问,处于保护状态,各自访问各自的。
动态运行时装入
程序运行过程中,需要加载其他的资源,对这部分资源重新链接并进行装入。
需要注意的是内存不够的时候有个内存扩充的技术
内存扩充
- 覆盖:动态变化的,不断覆盖的。
- 加载新的文件进来,放入覆盖区。
- 新进来的内容,把原来的内容覆盖掉。
- 交换:访问频率比较低的放入到外存中,访问频率高的放入内存中。
- 从硬盘上开一个缓存。
- 加载的内容放在硬盘缓冲中。
内存分配
连续分配
分配一块内存地址连续的内存空间。
单一连续分配
内存空间分成两大部分:系统区、用户区
-
系统区:低地址,内存的起始地址
-
用户区:高地址,系统加载完成后,加载用户进程的地址。
单一:有且只有一个用户进程,占用了整个用户区空间。
- 优点:
- 实现简单
- 无外部碎片,都没有其他用户进程了,也就没有“外部”了。
- 不一定需要内存保护
- 缺点:
- 只能用于单用户、单任务OS
- 有内部碎片,内部占用不一定是连续的。
- 存储器利用率低
固定分区分配
固定大小的分区,每个分区的大小不一定相等。其实就是单一连续分配的多进程场景。
- 优点:
- 实现简单。
- 无外部碎片。
- 缺点:
- 较大用户程序时候,需要采用“内存扩充-覆盖”技术,性能降低。
- 会产生内部碎片,利用率低。
动态分区分配
需要多少,分多少,需要记录内存的使用情况,需要按照算法选择分区分配,需要进行分区回收。
采用空闲分区表记录内存的使用情况。
选择分区的算法:
- 首次适应算法:按起始地址递增查找到一个可以容纳进程申请的大小的分区。
- 综合性能最好,开销小;
- 不需要对空闲分区重排序。
- 最佳适应算法:按最小空闲空间依次增大查找到一个可以容纳进程申请大小的分区。
- 更容易满足大进程需求;
- 小碎片多,开销大,需要重排序。
- 最坏适应算法:按照最大空闲空间依次减小查找到一个可以容纳进程申请大小的分区。
- 小碎片少;
- 不利于大金川,开销大。
- 临近适应算法:从上次查找的未知往后查找到一个可以容纳进程申请大小的分区。
- 不用每次从头部查找,开销小;
- 会使高地址大分区被用完。
非连续分配
分配一块内存地址不连续的内存空间,尽可能的利用所有分区。
分页
分页是把整个虚拟和物理内存空间切成一段段固定尺寸的大小 。这样一个连续并且尺寸固定的内存空间,我们叫 页 ( Page )。在 Linux 下,每一页的大小为 4KB
。
由于内存空间都是预先划分好的,也就不会产生间隙非常小的内存,那么释放的内存都是以页为单位释放的,也就不会产生无法给进程使用的小内存。
如果内存空间不够,操作系统会把其他正在运行的进程中的「最近没被使用」的内存页面给释放掉,也就是暂时写在硬盘上,称为 换出 ( Swap Out )。一旦需要的时候,再加载进来,称为 换入 ( Swap In )。所以,一次性写入磁盘的也只有少数的一个页或者几个页,不会花太多时间,内存交换的效率就相对比较高。
物理页和逻辑页对应做好映射,那么我们在加载程序的时候,就不再需要一次性都把程序加载到物理内存中。我们完全可以在进行虚拟内存和物理内存的页之间的映射之后,并不真的把页加载到物理内存里,而是只有在程序运行中,需要用到对应虚拟内存页里面的指令和数据时,再加载到物理内存里面去。
分段
程序由不同的逻辑组合起来的,按照这些逻辑段的形式分区。
- 缺点:
- 会产生内存碎片
- 不同的逻辑段占用分区大小不同,会导致产生很多不连续的小物理内存,新的程序可能无法装入。
- 程序装入后,并不是所有的逻辑段都经常使用,会造成内存浪费。
- 内存交换效率低
- 为解决碎片问题,有了内存交换,将不连续的空闲分区和占用的分区后面的进行交换,使得产生较大的空闲分区。
- 逻辑段很多,很容易产生内存碎片,swap过于频繁。
- 会产生内存碎片
段页式
分页和分段组合使用管理内存分配,就是段页式内存管理。
- 实现方式
- 分段:将程序划分成有逻辑意义的段。
- 分页:将每个段分页。
总结
程序=》进程:程序运行要编译成计算机识别的二进制指令然后链接打包成可执行文件最后装入内存中。
每个进程占用自己的内存地址彼此之前互不影响,当很多进程启用,内存空间资源紧张,则会通过内存扩张技术,覆盖或者交换内存空间,缓解空间资源紧张的问题。
系统对进程装入内存进行管理,可以连续的分配内存空间,不过会产生碎片,内存利用率也低,因此又有了不连续的分配内存空间,采用逻辑分段分区或分页分区又或者两者结合的段分页方式分配不连续的内存空间,将分区细化,降低内存碎片的产生以及提高了内存利用效率。