AkiraZheng's Time.

操作系统内存管理

Word count: 1.4kReading time: 4 min
2024/05/17

一、虚拟内存

1.1 为什么要有虚拟内存?

在单片机中是没有操作系统的,所以CPU会直接操作物理内存,而内存又是有限的,因此单片机中只能跑一个程序

而为了能够同时运行多个程序,我们需要操作系统,操作系统会为每个程序分配一块虚拟内存(可以实现进程间的内存隔离、解决物理内存不够的问题),这样每个程序都认为自己在独占物理内存,实际上是共享物理内存

最终每个进程的虚拟内存落盘到物理内存会通过页表来映射实现

CPU中存的是程序对应的虚拟地址信息,然后通过CPU中的MMU(内存管理单元,负责把虚拟地址映射成物理地址)映射成物理地址,进而再通过地址总线去访问物理内存

1.2 虚拟内存

当一个程序运行时,会允许一部分加载到实际的物理内存,而暂时不用的部分则会存放在磁盘(外存)

当执行到该进程的某部分代码出现缺页时,操作系统会产生一个缺页异常,并由用户态进入内核态磁盘上的相关数据加载到物理内存中,然后再返回用户态继续执行

这种技术就是虚拟内存技术,可以根据页的大小(Linux下一般为4KB)将程序进行分割,然后不连续地加载到物理内存

1.3 内存分页

内存分页前还有内存分段内存分段是将程序分为代码段、数据段、堆栈段等,它的好处是能产生连续的空间,但是内存分段会导致内存碎片问题,也就是大小不一的内存块会导致内存利用率不高

因此衍生出了内存分页的方式,将程序按照固定大小的页进行分割,这种紧密的页表排列不会有外碎片的产生,很好地利用了宝贵的物理内存空间。但是由于最小单位是,当不足一页时会补全一页,导致内部碎片的产生

虚拟内存物理内存之间通过存储在MMU中的页表进行映射

在单级分页中,会把虚拟地址分为

  • 页号:用于索引页表中的页表项,用于查找物理内存中对应页的物理地址
  • 页内偏移:用于定位中的具体字节。偏移是相对量,所以在虚拟内存物理内存中的偏移是一样的

所以通过页表拿到物理地址后,再加上页内偏移就能得到具体的物理地址

在这种单级分页下

  • 虚拟内存的页大小 == 物理内存的页大小
  • 而每个页表项有4byte(32位系统下)

假设内存大小2^nbit,每个页表项的大小为2^mbit,则表示总共有2^n/2^m = 2^(n-m)页数,因此需要有2^(n-m)个页表项,也就是有(n-m)bit来记录对应的页号

因此页表的大小是逻辑空间页数乘以页表项的大小(一个页表项占多少bits),这种单级分页的方式会导致页表过大,因此在实际操作系统中会采用多级页表的方式

1.4 多级页表

单级页表无法定位到某个进程,因此需要给整个逻辑空间的虚拟地址空间都分配页表(放在CPU中),这样会导致页表过大(且每个进程都有自己的页表),CPU无法放下,可以选择将页表放在内存中,而将经常访问的页表放在CPU的TLB中

二级页表的方式是通过将页号分为两部分

  • 第一部分用于索引一级页表,通过一级页表找到二级页表物理地址
  • 第二部分用于索引二级页表,通过二级页表找到实际物理地址

这样的话,页表的大小就变成了一级页表的大小 + 二级页表的大小,而一级页表中不存在的页则不会占用二级页表的空间,这样就减小了总页表的大小(页表还是放在内核态空间中)

在分级的机制下,假设只有 20% 的一级页表项被用到了,那么页表占用的内存空间就只有 4KB(一级页表) + 20% * 4MB(二级页表)= 0.804MB,这对比单级页表的 4MB 是不是一个巨大的节约?

1.5 页的换入换出

当程序运行时,内存空间不够时:

  • 操作系统会将正在运行的某个进程中不常用的页物理内存换出到**磁盘(外存)**上
  • 然后将需要的页磁盘换入物理内存

二、内存分配(malloc)

在文章内存池设计中已经有详细的介绍,这里就不再赘述

三、mmap

mmap在文章浅聊一下mmap延申的内存映射问题中已经有详细的介绍,这里就不再赘述

参考:内存管理

CATALOG
  1. 一、虚拟内存
    1. 1.1 为什么要有虚拟内存?
    2. 1.2 虚拟内存
    3. 1.3 内存分页
    4. 1.4 多级页表
    5. 1.5 页的换入换出
  2. 二、内存分配(malloc)
  3. 三、mmap