Linux内核(内存管理篇)

内存管理

页表项(PTE)

image-20251113165506677

拆解后分两部分:

(1) PFN(物理页号)

就是哪个物理页,存放在 PTE 的高 52 位(细节依赖 CPU)。

物理地址 = PFN << 12
(因为每页 4KB)

(2) flag bits(权限/状态位)

常见的标志位包括:

名称 含义
P Present 是否在内存中
R/W 可写 是否允许写
U/S 用户态/内核态 是否允许用户态访问
NX Non-Execute 是否禁止执行
A Accessed 是否被访问
D Dirty 是否被写过
PAT caching mode 缓存策略
Global 全局页 TLB 不会在切换 CR3 时刷新
COW Linux软件层标志 写时复制,内核组织在更高层 meta 信息

这些位让 CPU 知道如何处理对该页的内存访问。

例:
PTE 中 R/W=0 → 页只读
PTE 中 NX=1 → 页不可执行
PTE 中 Present=0 → 页不在内存,引发 page fault,从 swap/load-in 再填充页表

反向映射(RMAP)技术

基本概念

  • 正向映射

    当进程分配内存并发生写操作时,会分配虚拟地址并产生缺页,进而分配物理内存并建立虚拟地址到物理地址的映射关系, 这个叫正向映射。

  • 反向映射

    反过来, 通过物理页面找到映射它的所有虚拟页面叫反向映射(reverse-mapping, RMAP)。

为什么需要反向映射? 主要是为了内存回收。在操作系统中,多个进程的虚拟地址可能映射到同一个物理页(例如共享内存、写时复制等)。当内核需要回收一个物理页时,它必须修改所有映射了该页的页表项,使其无效或指向其他位置。如果没有反向映射,内核将不得不遍历所有进程的页表来寻找映射,这是极其低效的。

Linux2.4没有反向映射
在linux2.4内核中没有反向映射的这个概念,当时为了找到一个物理页面对应的页表项就需要遍历系统中所有的mm组成的链表,然后再遍历每一个mm的每一个vma看这个vma是否映射了这页,这个过程相当低效,最坏情况不得不遍历完所有的mm然后才能找映射到这个页的所有pte。

伙伴系统和slab分配器

在现代操作系统中,内存管理是支撑系统运行的核心支柱之一。它不仅决定了资源利用的效率,还直接影响性能、稳定性和应用程序的体验。在 Linux 内核中,内存管理通过分层设计实现了高效与灵活的平衡,其中 伙伴系统(Buddy System) 是物理内存分配的基础机制。无论是用户态程序通过 malloc() 请求内存,还是内核态创建进程描述符、分配文件缓冲区,背后都离不开伙伴系统的支持。

伙伴系统

Linux内核中使用伙伴系统(buddy system)来分配以页为单位的内存。

首先我们来说一下使用伙伴系统的原因,也就是解释一下内存分配时的内存碎片问题。内存碎片即“碎片的内存”,它分为外碎片内碎片,内存碎片描述一个系统中所有不可用的空闲内存,这些碎片之所以不能被使用,是因为负责动态分配内存的分配算法使得这些空闲的内存无法使用,这一问题的发生,原因在于这些空闲内存小且以不连续方式出现在不同的位置。因此这个问题的或大或小取决于内存管理算法的实现上。

外碎片

外部碎片指的是还没有被分配出去(不属于任何进程),但由于太小了无法分配给申请内存空间的新进程的内存空闲区域。

image-20251224112002335

内碎片

内部碎片就是已经被分配出去(能明确指出属于哪个进程)却不能被进程利用的内存空间。也就是分配给进程的内存空间过大,进程原本不需要这么多内存。

image-20251224112406247

slab分配器

内存回收

内存回收的方式

需要注意的是,我们这里提到的内存回收指的物理内存管理的逻辑。

1.直接内存回收:在编程语言或操作系统级别手动回收不再使用的内存资源。在编程语言中,就像用户程序通过free函数释放曾经通过malloc函数分配的内存一样。在操作系统层面,直接内存回收通常由垃圾回收器(Garbage Collector)来完成。垃圾回收器会自动检测并回收不再使用的对象所占用的内存空间,以减少内存泄漏和资源浪费。

2.定期扫描回收(kswapd):定期扫描回收(kswapd)是Linux内核中的一个守护进程,用于管理系统内存和交换空间。它负责检查当前内存使用情况,并在需要时进行页面回收或交换页面到磁盘上的交换分区。

3.OOM机制(out of memory):OOM机制是在内存不足时,内核使用了kswapd回收内存后仍然不够分配内存,就会触发OOM机制强制杀死占用内存最多的程序

定期扫描回收(kswapd)

kswapd 是一个内核线程,在内存不足时负责在后台进行内存回收,这个过程发生在后台,因此是异步发生,不会阻塞进程。

内核对内存的容量设置了三个阈值:

  • 页最小阈值(pages_min)
  • 页低阈值(pages_low)
  • 页高阈值(pages_high)

当内存大于 pages_high 时,表示此时系统内存足够,不会进行内存回收。

当内存小于 pages_low 时,表示此时内存存在压力,会触发 kswapd0 进行后台内存回收,直到 pages_high 为止

当内存小于 pages_min 时,表示此时用户内存耗尽,会触发直接内存回收,进程被阻塞。

直接内存回收

OOM

Reference

『面试问答』:什么是内存碎片?如何减少内存碎片?_牛客网


Linux内核(内存管理篇)
http://yzsandw.com/2025/11/13/linux内核-内存调度篇/
作者
5Y2z
发布于
2025年11月13日
许可协议