xarray
[TOC] lib/xarray.c eXtensible Array (XArray) 可扩展数组历史与背景这项技术是为了解决什么特定问题而诞生的?XArray(eXtensible Array,可扩展数组)的诞生是为了替代并改进Linux内核中一个非常重要但使用起来十分复杂的数据结构——Radix Tree。Radix Tree长期以来是内核(尤其是页缓存 page cache)用于管理稀疏长整型索引到指针映射的核心组件,但它存在诸多问题: 复杂的API和使用模式:Radix Tree的API不够直观,开发者需要自行处理很多棘手的边界情况,比如存储NULL指针、处理特殊的“异常条目”(exceptional entries),以及管理并发访问的锁。这使得代码容易出错且难以维护。 锁机制外部化:Radix Tree本身不提供锁机制,使用者必须在外部实现自己的锁来保护数据结构,这增加了驱动和子系统开发者的负担。 内存预加载问题:为了在持有锁时避免睡眠(因分配内存可能导致睡眠),Radix Tree的使用者通常需要“预加载”节点内存,这种机制复杂且可能浪费内存。 ...
memblock
[TOC] mm/memblock.c: Linux内核的“拓荒时代”内存管理器mm/memblock.c 实现了一种极其早期的、简单的物理内存分配器,它在内核启动的“拓荒时代”——即在页分配器(伙伴系统)初始化之前——扮演着至关重要的角色。 可以将其想象成一个在建造正式仓库(伙伴系统)之前,用来管理建筑材料(物理内存)的临时账本和场地规划师。它的唯一使命是在最原始的环境下,为内核自身的初始化提供最基本的内存分配服务,并在完成使命后,将所有管理权平稳地移交给更高级的内存管理系统。 一、 核心问题:为什么需要 memblock?在内核启动的极早期(start_kernel 函数刚开始执行时),真正的内存管理子系统(如伙伴系统、Slab 分配器)还完全不存在。这些高级系统本身就需要分配内存来存放它们复杂的数据结构(如 mem_map 数组、kmem_cache 结构等)。这就产生了一个“先有鸡还是先有蛋”的问题: 为了初始化内存管理器,你需要分配内存。 但为了分配内存,你需要一个已初始化的内存管理器。 memblock 就是为了打破这个循环而存在的。它是一个极其简单的...
list_lru
[TOC] list_lru: Linux内核的可扩展对象缓存管理器list_lru 是 Linux 内核提供的一套可扩展的、近似 LRU (Least Recently Used) 缓存列表管理机制。它专门设计用来高效地管理大量、小型、生命周期不一的内核对象,例如目录项缓存(dentries)和索引节点缓存(inodes)。 可以将其想象成一个特殊的“图书馆卡片目录系统”,这个系统需要被许多图书管理员(CPU核心)同时、频繁地访问,并且需要一种高效的方式来找出那些最久未被使用的卡片(对象)以便回收。 一、 核心问题:为什么需要 list_lru?在理解 list_lru 的设计之前,必须先明白它要解决的核心问题:在多核环境下的锁竞争。 一个朴素的 LRU 列表实现通常是这样的: 维护一个全局的双向链表。 当一个对象被访问时,将它从链表中的当前位置移到链表头(表示最新使用)。 当需要回收内存时,从链表尾部(表示最久未使用)开始移除对象。 这种实现在单核系统上工作得很好。但在现代多核系统中,会产生一个巨大的性能瓶颈:所有 CPU 核心都必须竞争同一个全局锁来修改这个链表...
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(或某个起始偏移)到系统最大物理内存地址之间的所有页...
filemap
[TOC] mm/filemap.c: Linux 页缓存 (Page Cache) 的心脏mm/filemap.c 是 Linux 内核中实现和管理页缓存 (Page Cache) 的核心源文件。页缓存是 Linux I/O 性能的基石,它将磁盘上的文件内容缓存到物理内存(RAM)中,使得后续对同一文件的读写操作可以直接在内存中完成,从而避免了缓慢的磁盘 I/O。 可以把 mm/filemap.c 想象成一个高效的“图书管理员”,它负责管理一个巨大的图书馆(页缓存),图书馆里的每一页书(struct page)都对应着磁盘文件上的某一页内容。 一、 核心职责mm/filemap.c 的代码几乎参与了所有与文件 I/O 相关的内存操作,其核心职责包括: 页缓存的查找与插入 (Finding and Inserting): 当需要读取文件数据时,它负责在页缓存中查找是否已缓存了对应的页面。如果找到(Cache Hit),则直接返回内存页;如果未找到(Cache Miss),则负责分配一个新的物理页,并将其插入到页缓存中,准备从磁盘加载数据...
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...
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“一切皆文件”的设计...
zlib
[TOC] lib/zlib_inflate/inflate.c & lib/zlib_deflate/deflate.c DEFLATE压缩与解压缩历史与背景这项技术是为了解决什么特定问题而诞生的?内核中集成的 zlib 库是为了提供一个通用、可靠且经过充分验证的数据压缩和解压缩方案。数据压缩的根本目标是通过算法减少数据占用的存储空间或网络传输带宽。在内核这个层面,引入 zlib 主要解决了以下具体问题: 节省存储空间:对于存储受限的系统(尤其是早期的嵌入式设备),需要通过压缩文件系统来存储更多的内容。 加快启动速度:Linux内核镜像本身可以被压缩。在启动时,一个小型解压程序(stub)会先解压内核镜像到内存中再执行。虽然解压需要CPU时间,但从慢速存储设备(如早期的磁盘、Flash)读取一个较小的压缩文件所需的时间,远少于读取一个大的未压缩文件的时间,因此总体上加快了启动速度。 提高网络效率:在一些网络协议(如PPP)中,对传输的数据进行压缩可以显著减少网络带宽的占用。 内存优化-:通过在内存中创建压缩的块设备(RAM...
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框架的情况...








