init
[TOC] Linux 内存模型之基石:FLATMEM 深度解析FLATMEM 是 Linux 内核中最基础、最常用,也是最高效的内存模型。正如其名,“平坦内存”模型假定系统的物理内存是一个单一、连续、不存在大间隙的地址空间。 一、 核心原理:mem_map 数组FLATMEM 模型的全部精髓都围绕着一个核心数据结构:一个巨大的、全局的 struct page 数组,通常被称为 mem_map。 什么是 struct page? 在 Linux 内核中,物理内存不是按字节管理的,而是按固定大小的块来管理的,这个块被称为页帧 (Page Frame)(通常是 4KB)。 内核为每一个物理页帧都分配了一个 struct page 描述符。这个结构体包含了该物理页帧的所有元数据,例如:它的引用计数、它是否是脏页、是否被锁定、属于哪个地址空间映射等。 mem_map 的作用 FLATMEM 模型在内核启动的极早期,会分配一个足够大的连续内存区域,用来存放一个 struct page 数组。这个数组的大小足以覆盖从物理地址 0(或某个起始偏移)到系统最大物理内存地址之间的所有页...
memblock
[TOC] mm/memblock.c: Linux内核的“拓荒时代”内存管理器mm/memblock.c 实现了一种极其早期的、简单的物理内存分配器,它在内核启动的“拓荒时代”——即在页分配器(伙伴系统)初始化之前——扮演着至关重要的角色。 可以将其想象成一个在建造正式仓库(伙伴系统)之前,用来管理建筑材料(物理内存)的临时账本和场地规划师。它的唯一使命是在最原始的环境下,为内核自身的初始化提供最基本的内存分配服务,并在完成使命后,将所有管理权平稳地移交给更高级的内存管理系统。 一、 核心问题:为什么需要 memblock?在内核启动的极早期(start_kernel 函数刚开始执行时),真正的内存管理子系统(如伙伴系统、Slab 分配器)还完全不存在。这些高级系统本身就需要分配内存来存放它们复杂的数据结构(如 mem_map 数组、kmem_cache 结构等)。这就产生了一个“先有鸡还是先有蛋”的问题: 为了初始化内存管理器,你需要分配内存。 但为了分配内存,你需要一个已初始化的内存管理器。 memblock 就是为了打破这个循环而存在的。它是一个极其简单的...
nommu
[TOC] mm/nommu.c NO-MMU内存管理(NO-MMU Memory Management) 适用于无内存管理单元的系统历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了让Linux操作系统能够运行在没有**内存管理单元(MMU)**的简单微控制器(MCU)和嵌入式处理器上。标准的Linux内核设计严重依赖MMU来实现以下核心功能: 虚拟内存:为每个进程提供独立的、巨大的、线性的虚拟地址空间。 内存保护:利用硬件机制防止一个进程访问另一个进程或内核的内存空间,保障系统稳定性和安全性。 内存映射与分页:实现写时复制(Copy-on-Write)、按需分页(Demand Paging)和交换(Swapping)等高级内存管理技术。 许多低成本、低功耗的嵌入式处理器(如ARM Cortex-M系列)为了节省芯片面积和功耗,并不包含MMU。mm/nommu.c 及其相关代码提供了一套替代的、简化的内存管理模型,使得功能强大的Linux内核能够在这种受限的硬件上运行,这通常被称为uClinux(Micro-Controller Linux)。 它的...
page-writeback
[TOC] mm/page-writeback.c 页面回写(Page Writeback) 数据持久化的核心机制历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了解决一个计算机体系结构中的根本性矛盾:内存(RAM)与持久性存储设备(如硬盘、SSD)之间巨大的性能差距。 性能缓冲:应用程序向文件写入数据时,如果每次写入都必须等待慢速的存储设备完成,那么整个系统的性能和响应速度将变得无法接受。页面回写机制利用高速的内存作为写回缓存(Write-back Cache),允许write()系统调用将数据写入内存(即 Page Cache)后立即返回,从而极大地提升了应用程序的写入性能和系统吞吐量。 数据持久化:内存中的数据是易失的,断电后会丢失。因此,必须有一个可靠的机制,将在内存中被修改过的数据(称为“脏页”,Dirty Page)在合适的时机写回到持久性存储设备上,确保数据的最终安全性。 I/O效率优化:该机制可以将多次小的、离散的写入操作在内存中合并成一次大的、连续的写入操作,然后再提交给存储设备。这种**I/O合并(I/O...
page_alloc
[TOC] mm/page_alloc.c 伙伴系统内存分配器(Buddy System Memory Allocator) 内核物理内存管理的核心历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了解决操作系统内核中最根本的问题之一:如何高效、可靠地管理整个系统的物理内存(RAM)。内核自身及其服务的子系统(如进程管理、文件系统缓存、网络协议栈)都需要动态地申请和释放内存。mm/page_alloc.c 中实现的伙伴系统(Buddy System)旨在满足以下核心需求: 管理基本单位:将物理内存划分为固定大小的“页”(通常是4KB),并以此为基本单位进行管理。 提供连续内存:许多硬件设备(特别是进行直接内存访问DMA的设备)和某些内核数据结构要求得到的内存块在物理上是连续的。伙伴系统的设计目标之一就是能够分配不同大小的、物理连续的内存块。 对抗外部碎片:在长时间运行的系统中,频繁地分配和释放不同大小的内存块会导致物理内存中产生许多不连续的小空闲块。这种现象称为“外部碎片”,它会导致即使总的空闲内存很多,也无法满足一个较大连续内存的申请。伙伴系统通过其独特...
percpu
[TOC] mm/percpu.c Per-CPU Variables Management Per-CPU数据管理的核心实现历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了从根本上解决在多核(SMP)系统中并发访问共享数据所带来的性能瓶颈而诞生的。 锁争用(Lock Contention):在多核系统中,如果多个CPU核心频繁地更新同一个全局变量(例如,一个网络数据包统计计数器),它们必须使用锁(如自旋锁)来保护这个变量,以避免数据竞争。当核心数量增加时,对这个锁的争夺会变得非常激烈,导致CPU花费大量时间在等待锁上,而不是执行实际工作,从而严重限制了系统的扩展性。 缓存一致性开销(Cache Coherency Overhead):即使不使用锁(例如使用原子操作),也会有性能问题。当一个CPU核心修改了共享变量,它所在的缓存行(Cache Line)会被标记为“脏”(Modified)。根据缓存一致性协议(如MESI),其他CPU核心上该缓存行的副本必须被置为“无效”(Invalidated)。当其他CPU也想访问这个变量时,就必须从修改过的那个核...
shrinker
[TOC] mm/shrinker.c 内核缓存收缩器(Kernel Cache Shrinker) 响应内存压力的回调机制历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术以及其实现的“收缩器”(Shrinker)框架,是为了解决Linux内核中一个根本性的资源管理问题:如何在一个统一的框架下,回收由各种不同内核子系统所占用的内存缓存。 内核缓存的多样性:Linux内核不仅仅有用于缓存文件数据的页面缓存(Page Cache)。还有许多其他重要的缓存,例如用于加速路径查找的dcache、用于缓存文件元数据的inode缓存,以及Slab/Slub分配器自身为内核对象维护的缓存等。 缺乏统一回收接口:当系统物理内存(RAM)不足时,内存管理(MM)子系统需要释放一些内存。对于页面缓存,它有自己复杂的LRU(最近最少使用)算法来回收。但对于dcache、inode cache等“非页面缓存”的内存,MM子系统本身并不知道它们的内部结构,也不知道哪些对象是“可回收的”(例如,一个未被使用的dentry)。 解耦的需求:在没有Shrinker框架的情况...
shmem
[TOC] mm/shmem.c 共享内存文件系统(Shared Memory Filesystem) tmpfs与POSIX共享内存的基石历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术以及由它实现的tmpfs文件系统,主要是为了解决两大类问题:高性能的临时文件存储和高效的进程间通信(IPC)。 高速临时存储:传统的磁盘文件系统读写速度受限于物理硬件,速度较慢。很多程序在运行过程中需要创建临时文件(例如编译器中间文件、Web服务器的会话文件等),这些文件不需要持久化存储,在系统重启后即可丢弃。shmem通过在内存中实现一个完整的文件系统,提供了比磁盘快几个数量级的读写速度,极大地提升了这类应用的性能。 进程间通信(IPC):在shmem出现之前,Linux主要支持System V IPC标准的共享内存。POSIX标准则提出了一套基于文件系统的共享内存API(shm_open, mmap)。为了在内核中实现一个统一、高效的后端来支持这两种共享内存机制,shmem被开发出来。它通过将共享内存区域抽象成内存中的“文件”,完美地融入了Linux“一切皆文件”的设计...
swap
[TOC] mm/swap.c 交换机制(Swap Mechanism) 物理内存的虚拟扩展历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术以及其实现的交换(Swap)机制,是为了解决一个自计算机诞生以来就存在的根本性限制:物理内存(RAM)的大小是有限的。 运行大于物理内存的程序:在早期,如果一个程序需要比机器拥有的RAM更多的内存,它根本无法运行。交换机制通过将内存中不常用的部分临时存放到磁盘上,从而“欺骗”程序,让它以为自己拥有一个远大于实际物理内存的地址空间。这使得运行大型应用程序成为可能。 同时运行更多的程序:即使每个程序都能装入内存,但同时运行多个程序可能会迅速耗尽RAM。交换机制允许内核将处于空闲或等待状态的进程的内存换出到磁盘,从而为当前活动的进程腾出宝贵的物理内存,提高系统的并发能力和整体吞吐量。 系统休眠(Hibernation):为了实现休眠到磁盘(Suspend-to-Disk)功能,内核需要一个地方来存储整个系统内存的快照。交换空间(Swap Space)被自然地用作这个存储区域。 它的发展经历了哪些重要的里程碑或版本迭代?...
truncate
[toc] mm/truncate.c 页面缓存截断(Page Cache Truncation) 文件大小变更的核心内存管理历史与背景这项技术是为了解决什么特定問題而誕生的?这项技术是为了实现一个最基本、最核心的文件系统功能:更改文件的大小,特别是缩减文件(Truncation)。这是一个由POSIX标准规定的基础操作。mm/truncate.c专门负责处理这个操作在内存管理(Memory Management, MM)层面最复杂的部分:确保文件的内存表示(即页面缓存 Page Cache)与文件在磁盘上的新大小保持一致。 它解决了以下核心问题: 内存与磁盘同步:当用户调用truncate()或以O_TRUNC模式打开文件时,不仅需要通知文件系统释放磁盘上的数据块,还必须精确地从内核的页面缓存中移除或修改对应的缓存页。否则,应用程序可能会读到已经被“删除”的陈旧数据,或者脏页(Dirty Page)可能会错误地将已删除的数据写回磁盘。 处理边界条件:文件截断不总是以页面大小(通常是4KB)对齐的。mm/truncate.c必须能精确处理部分被截断的页面,即一个页面中...









