Linux 内存管理「一」|周末学习

文章正文第一句:「本文已参与 周末学习计划,点击查看详情 」


最近在整理有关 OS 的知识,主要是为了理清程序在运行过程中一些细节。

本篇梳理一下 Linux 中的内存管理。

进程的地址空间分布

在 Linux 下,每个进程都拥有独立的虚拟地址空间。具体的分配布局如下:

自下而上整个分配有:

  • Text Segment:存储程序的二进制代码。
  • Data Segment:存储已初始化的全局数据。
  • BSS Segment:存储未初始化的全局数据。
  • Heap:堆内存,向高地址增长。
  • Memory Mapping Region:mmap 系统调用映射内存的地址区间。
  • Stack:栈内存,向低地址增长。
  • Undefined Region:未定义的地址区间,用于将来扩展 64 位地址空间。
  • Kernel Space:内核地址空间。

虚拟地址

上面也说了,进程地址空间其实就是虚拟的内存地址空间,这个就是我们所说的 虚拟化

每个进程在运行中都任务自己拥有了很大的地址范围,实际上最终在获取地址下的数据,还是得到真实地址下去获取,而且实际上进程使用的内存分散在物理内存的不同区域,还可能在磁盘(不然怎么叫虚拟化)。

关键操作就出来了:虚拟地址怎么转换成物理地址?

单说就是,每个进程都有一套自己的页表,虚拟地址通过查表的方式转换成物理地址:

页表转换

虚拟地址既然要转换为物理地址,就要按照物理地址的组织形式。物理内存是分页管理的,物理地址是内存区域的划分,一般内存页大小是 4KB

而虚拟地址到物理地址的转换,也就是一个虚拟内存页某块区域地址到物理内存页某块区域地址的转换:

以上在同一个进程中都有这么一个 page table 。我们计算一下目前这种直接匹配下的内存占用:

以 32 位的虚拟地址为例,页内偏移部分需要 12 位(2^12B = 4KB),虚拟页号部分是 20 位。因此,这个一维数组需要 2^20 个元素,那个元素大小是 4B,占用内存 2^20 * 4B = 4MB

一个进程光页表分配就 4MB,一个 32 位的系统,最大的内存也才 4GB,所以目前这种直接匹配肯定是不行的。

为了解决这种一级页表占用内存过多的问题,Linux 采用了一种“多级页表”的结构。

多级页表是将页表目录作为索引,加到虚拟页号前面。进程一开始只需要建立最顶级的页表,只有当实际需要用到具体的虚拟地址时通过缺页中断(page fault)建立完整的映射,这样大幅度减少一些没必要的虚拟到物理的转换占有。


下篇我们讲讲 缺页中断,page cache,刷脏 。。。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享