Memory
TLB
32 位的操作系统的寻址范围为 4G,64的操作系统用户空间和内核空间寻址范围为 128T
用户空间包含有五个部分,分别是
- 只读段,包含代码和常量
- 数据段,包括全局变量
- 堆,包括动态分配的内存,从低地址开始向上增长
- 文件映射段,包括动态库、共享内存等,从高地址开始向下增长
- 栈,包括局部变量和函数调用的上下文。栈的大小一般是固定的,一般是 8MB
每个进程都有自己的页表,记录相关的映射关系,大小一般是 4KB 虚拟内存向物理内存映射的关系图是:
其中 MMU(Memory Management Unit)是一种硬件模块,用于在 CPU和内存之间实现虚拟内存管理。 其主要功能是将虚拟地址转换为物理地址,同时提供访问权限的控制和缓存管理等功能。 放在整个大系统多核架构里面,每个处理器内置了MMU模块,MMU模块包含了 TLB 和TWU两个子模块。
为了加速内存映射,操作系统会将 TLB(Translation Lookaside Buffer)作为 MMU 页表中的高速缓存,进而提高 CPU 的内存访问性能
因此CPU读取数据的过程如图:
Page Fault
假如目标内存页在物理内存中没有对应的页帧或者存在但无对应权限,CPU 就无法获取数据,这种情况下CPU就会报告一个缺页错误。一般的缺页错误有以下三种:
Hard Page Fault
需要访问的内存不在虚拟地址空间,也不在物理内存中,需要从慢速设备载入。
从磁盘 Swap in 回到物理内存也就是 hard page fault
Swap in:当CPU要执行的指令被发现已经swap out到了磁盘中, 这时就需要从磁盘把这些指令再swap in到物理内存中。
Swap out:当物理内存不够时,把一些物理内存page中的内容写入到磁盘,以腾出一些空闲的page;
这两个操作是比较耗时的。
Soft Page Fault
需要访问的内存不在虚拟内存中而是在物理内存中,那么就在 MMU 中创建出相关的映射关系即可。
当一个进程在调用 malloc 获取虚拟空间地址后,首次访问该地址会发生一次soft page fault。
通常是多个进程访问同一个共享内存中的数据,当某些进程还没有建立起映射关系,访问时也会出现soft page fault。
Segment Fault
也称为 segment fault,指进程需要访问的内存地址不在它的虚拟地址空间范围内,属于越界访问,内核就会报 segment fault 错误。
造成 segment fault 的原因可能有以下几种:
- 堆栈溢出;
- 内存访问越界,如数组下表错误访问越界;使用strcpy/strcat/sprintf/strcmp 等字符串操作函数导致的读写越界,应尽量使用strncpy/strncat/snprintf/strncmp 等函数防止读写越界;
- 非法指针:野指针,错误的指针转换等;
- 多线程读写的数据未加锁保护,或使用了线程不安全的函数。
惰性分配
惰性分配,即系统会快速回应需要内存的进程表示你的申请是有效的,但此时并不会为该进程真正分配出内存空间,而是在该进程真正使用到这段内存时才真正分配,这就是惰性分配思想。操作系统采取惰性分配的好处个人认为如下:
避免某些进程空占着内存资源。有些进程在初始化时就先分配了大量内存,但这些内存空间也许要等到某些条件触发时才会利用上,也有可能到进程退出时也用不到这些内存,因此为了保证内存的使用率,惰性分配很有必要。以一个“延时满足”的思想解决了内存消耗过快的问题。
overcommit
但是延迟分配是存在问题,问题是如果已经认可了这个进程需要分配内存,但实际上系统的内存资源(物理内存+Swap)已经耗尽,无法进行分配了。
Overcommit(内存超配) 是一种操作系统内存管理策略,它允许系统分配比实际物理内存(RAM)+ 交换空间(Swap)总量更多的虚拟内存给进程。这种机制的核心思想是:大多数程序实际使用的内存不会达到其申请的最大值,因此可以“超额承诺”内存资源以提高利用率。
出现内存不足的情况的时候会进行:
- OOM killer:随机杀死一些进程
- 拒绝访问
调度算法
- FIFO
- OPT:Optimal
- Clock
- LFU:Least Frequently Used
- LRU:Least Recently Used