文章目录
操作系统内存管理目标
计算机所有的设备和CPU通信都需要经过内存,内存管理的目标包括:
存取速度
cache是一种存储速度比内存快,容量比内存小得多的存储收器。利用cache可以解决快速CPU和慢速内存间矛盾,CPU首先从cache中读取数据,cache miss之后再从内存中读取。cache可以分为三级,前两级集成在CPU核内部,三级缓存位于主板上,由多核共享。
操作正确
内存正确的分配和回收
地址保护策略
从安全隔离角度考虑,禁止进程访问内核内存空间和其他进程内存空间。操作系统一般不干预CPU对内存的访问,因此这一块功能一般由硬件实现,比如基址寄存器和限长寄存器,前者记录该进程的基址地址、后者记录进程最大可访问的内存长度,这两寄存器的值只能由特权指令加载。进程在调用用户态API时,访存地址须位于上述地址范围内,超过会触发中断,从而进程异常退出。
因为逻辑地址值等于从起始逻辑地址的偏移,等于逻辑地址长度,所以使用逻辑地址和内存限长比较,就可以判断出地址是否越界
地址转换
实现逻辑地址、物理地址之间的转换
地址空间和地址转换
逻辑地址/相对地址/虚拟地址:面向程序的地址,地址从0开始递增,每条指令的地址就是相对首条地址的偏移。
物理地址/绝对地址:内存单元的实际地址。
逻辑地址空间:逻辑地址的合集
物理地址空间:物理地址的合集
地址转换:CPU操作进程的时候,用的是逻辑地址,逻辑地址经过内存管理单元(MMU)转换成物理地址,转换逻辑是:物理基址+逻辑地址,其中物理基址从页表从获取。
使用逻辑地址的好处
每次加载程序的时候不用修改代码中的地址,只要修改基址就行。
什么时候进行地址转换
程序从代码到进程经过编译–>加载–>运行,三个阶段,如果在编译或加载阶段进行地址转换,程序运行时的地址就确定了,一旦修改程序将无法运行,所以地址转换在运行时最为合适。
进程加载到内存之后的地址还是逻辑地址,执行某一条指令时,如call x,才进行地址转换,转换由MMU进行,物理起始地址记录在基址寄存器(重定位寄存器)中,访问实际地址的时候,只需将物理基址加上逻辑地址,就能得到物理地址。
CPU访问的地址是逻辑地址,物理地址对CPU是不可见的。
连续的内存分配
操作系统对进程的内存分配具备如下特性:
- 进程内部的内存是连续的(在不考虑分段和分页的前提下)
- 进程和进程之间的内存是连续的
内存分配策略
内存分配策略包括固定分区内存分配策略和可变分区内存分配策略,前者是老的操作系统在当时内存小、进程数少的环境下的分配策略,现在已经不用了。
固定分区内存分配策略
操作系统事先将内存分割成大小不同的分区,操作系统根据进程所占内存大小,选择合适的分区,分配给进程。并且维护一个分区表,记录分区的基址、大小、是否已分配。每个分区只能被用于一个进程,用不完的内存不会重新分配,产生碎片。
回收分区的时候,只需要把已分配的标志修改即可。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iyBRhqZT-1654440208006)(${img}/image-20220604221844815.png)]
可变分区内存分配策略
内存按需分配,即进程占多大空间,就从内存中开辟一个相同大小的连续空间给进程。操作系统记录两张表,一张记录可用内存的基址和长度,一张记录已分配表的基址、长度和被哪个进程占用。未被分配的连续内存被称为孔洞,计算机初始情况下只有一个孔洞,大小是整个内存大小,后续不断分配和回收后,形成多个不连续的孔洞集合。
分配策略包括:
- 首次适应:分配首个满足大小的孔洞,效率高,无需遍历内存
- 最佳适应:分配最小的满足大小的孔洞,浪费小,需要遍历内存
- 最坏适应:分配最大的孔洞,孔洞剩余部分最大概率能被利用,需要遍历内存
内存碎片
内存碎片指很小的难以被利用的内存分区。碎片分为:
- 内部碎片:针对固定分区内存分配策略
- 外部碎片:针对可变分区内存分配策略,外部碎片可以通过压缩技术优化,
实例
比如一个main函数:
#include <stdio.h>
int
main(int argc, char **argv)
{
int a = 1 + 1;
return 0;
}
首先编译成.o文件:
gcc -g -c main5.c
然后反编译成汇编代码:
[root@localhost test]# objdump -d main5.o
main5.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 89 7d ec mov %edi,-0x14(%rbp)
7: 48 89 75 e0 mov %rsi,-0x20(%rbp)
b: c7 45 fc 02 00 00 00 movl $0x2,-0x4(%rbp)
12: b8 00 00 00 00 mov $0x0,%eax
17: 5d pop %rbp
18: c3 retq
其中第一列为指令的逻辑地址,第二列为指令码。可以看到地址从0开始,属于逻辑地址,CPU处理的也是逻辑地址,如何转换成物理地址应用程序并不关心。
总结自:
https://www.bilibili.com/video/BV1bf4y147PZ?p=21