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“一切皆文件”的设计...
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框架的情况...
swap
[TOC] mm/swap.c 交换机制(Swap Mechanism) 物理内存的虚拟扩展历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术以及其实现的交换(Swap)机制,是为了解决一个自计算机诞生以来就存在的根本性限制:物理内存(RAM)的大小是有限的。 运行大于物理内存的程序:在早期,如果一个程序需要比机器拥有的RAM更多的内存,它根本无法运行。交换机制通过将内存中不常用的部分临时存放到磁盘上,从而“欺骗”程序,让它以为自己拥有一个远大于实际物理内存的地址空间。这使得运行大型应用程序成为可能。 同时运行更多的程序:即使每个程序都能装入内存,但同时运行多个程序可能会迅速耗尽RAM。交换机制允许内核将处于空闲或等待状态的进程的内存换出到磁盘,从而为当前活动的进程腾出宝贵的物理内存,提高系统的并发能力和整体吞吐量。 系统休眠(Hibernation):为了实现休眠到磁盘(Suspend-to-Disk)功能,内核需要一个地方来存储整个系统内存的快照。交换空间(Swap Space)被自然地用作这个存储区域。 它的发展经历了哪些重要的里程碑或版本迭代?...
slub
[TOC] mm/slub.c SLUB内存分配器(The SLUB Allocator) 现代内核对象缓存的核心历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术以及它所实现的SLUB分配器,是为了解决内核中一个基础且关键的性能问题:如何高效地分配和释放大量小的、固定大小的内存对象。 对抗内部碎片(Internal Fragmentation):内核需要频繁创建大量的小对象(如inode, dentry, task_struct等),它们的大小通常远小于一个物理内存页(通常是4KB)。如果直接使用页分配器(Buddy System)来为这些小对象分配整个页,会造成巨大的内存浪费。例如,为一个128字节的对象分配一个4096字节的页,97%的内存就被浪费了。 提升分配性能:通用的内存分配器需要处理任意大小的请求,其算法相对复杂。而对于特定类型的对象,我们可以创建一个专用的“对象缓存池”。SLUB分配器就是这种缓存池的实现者。 利用对象构造/析构:很多内核对象在首次使用时需要进行初始化。SLUB框架允许在创建缓存时指定一个“构造函数”(construc...
util
[TOC] mm/util.cinit_user_buckets: 初始化memdup_user的专用内存桶此代码片段的作用是在内核启动的早期阶段, 创建一个专用的、高性能的内存分配器(一个kmem_buckets实例), 并将其赋给全局指针user_buckets。这个专用的分配器被命名为"memdup_user", 意味着它被内核中的memdup_user()函数和相关函数独占使用, 目的是优化从用户空间复制数据到内核空间时的小块内存分配性能。 工作原理: memdup_user()是一个非常常见的内核函数, 用于安全地从用户空间拷贝一块数据到内核新分配的内存中。这个操作在处理系统调用参数、网络数据包等场景中被频繁调用, 且请求分配的内存大小各不相同。 标准的通用内存分配器kmalloc()虽然功能强大, 但对于这种极其频繁、大小多变的小块内存请求, 其内部的查找和管理开销可能会成为性能瓶颈。 kmem_buckets (内存桶) 则是一种更轻量级、更快的专用分配器, 类似一个内存池(memory pool)。 它内部预先维护了一系列”桶”(b...
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必须能精确处理部分被截断的页面,即一个页面中...
vmstat
[TOC] mm\vmstat.cinit_mm_internals 初始化内存管理(MM)子系统中,那些依赖于其他核心子系统(如workqueue、cpuhp)已经建立的、更深层次的内部组件。它并非内存管理的最早期初始化(如物理页帧分配器的建立),而是一个第二阶段的、功能性的初始化 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364/* * 这是一个静态的、仅在初始化阶段调用的函数,负责初始化内存管理(MM)的内部组件。 */void __init init_mm_internals(void){ /* ret: 用于接收函数返回值,__maybe_unused属性告诉编译器,在某些配置下 * (如非SMP),这个变量可能未被使用,不要因此产生警告。*/ int ret __maybe_unused; /* * 为MM子系统分配一个名为"mm_percpu_...
fs-writeback
[TOC] fs-writebackfs-writeback.c 是 Linux 内核中负责处理文件系统数据写回(writeback)机制的核心模块。它的主要功能是管理脏页和脏 inode 的写回操作,以确保数据从内存缓冲区最终写入磁盘。以下是对其原理、使用场景、优缺点以及其他方案的详细阐述: 原理 脏页与脏 inode: 当文件系统中的数据被修改时,内核会将这些修改暂时存储在内存中(页缓存或 inode 缓存),并标记为“脏”。 脏页指的是页缓存中未写入磁盘的修改数据,脏 inode 则是文件元数据(如时间戳、权限等)的未写入部分。 写回机制: fs-writeback.c 通过后台线程(flusher threads)定期扫描脏页和脏 inode,并将它们写入磁盘。 写回操作可以是异步的(WB_SYNC_NONE),也可以是同步的(WB_SYNC_ALL),具体取决于调用场景。 核心组件: bdi_writeback: 表示一个设备的写回上下文,管理该设备的脏页和脏 inode。 wb_writeback_work: 描述写回任务的结构体,包括写回页数、...
filesystems
[toc] fs/ VFS - 虚拟文件系统(Virtual Filesystem) 内核统一的文件系统抽象层历史与背景这项技术是为了解决什么特定问题而诞生的?虚拟文件系统(Virtual Filesystem Switch, VFS)是Linux内核最核心、最强大的子系统之一。它的诞生是为了解决一个根本性的问题:如何让应用程序以一种统一的方式来访问各种不同类型的文件系统。 在VFS出现之前,操作系统如果想支持一种新的文件系统(例如,从Minix文件系统切换到ext文件系统),可能需要重写大量与文件操作相关的代码。应用程序也可能会与特定的文件系统实现产生耦合。VFS通过创建一个通用的抽象层来解决这个问题: 对应用程序的统一接口:无论底层是ext4、XFS、Btrfs、NFS(网络文件系统),还是一个USB U盘上的FAT32,应用程序都使用同样标准的系统调用(open, read, write, close, stat等)来操作文件。应用程序完全不需要知道底层文件系统的具体类型和实现细节。 对文件系统驱动的统一接口:VFS定义了一套标准的“插件”接口。任何想要被...
debug
[TOC] arch/arm/include/debug/stm32.Saddruart 添加debug串口地址1234.macro addruart, rp, rv, tmp ldr \rp, =CONFIG_DEBUG_UART_PHYS @ physical base ldr \rv, =CONFIG_DEBUG_UART_VIRT @ virt base.endm CONFIG_DEBUG_UART_PHYS 和 CONFIG_DEBUG_UART_VIRT1234567891011121314151617//arch/arm/Kconfig.debugconfig DEBUG_UART_VIRT default DEBUG_UART_PHYS if !MMUconfig DEBUG_UART_PHYS default 0x40011000 if STM32F4_DEBUG_UART || STM32F7_DEBUG_UART || \ STM32H7_DEBUG_UARTconfig STM32H7_DEBUG_UART b...








