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也想访问这个变量时,就必须从修改过的那个核...
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必须能精确处理部分被截断的页面,即一个页面中...
page_alloc
[TOC] mm/page_alloc.c 伙伴系统内存分配器(Buddy System Memory Allocator) 内核物理内存管理的核心历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了解决操作系统内核中最根本的问题之一:如何高效、可靠地管理整个系统的物理内存(RAM)。内核自身及其服务的子系统(如进程管理、文件系统缓存、网络协议栈)都需要动态地申请和释放内存。mm/page_alloc.c 中实现的伙伴系统(Buddy System)旨在满足以下核心需求: 管理基本单位:将物理内存划分为固定大小的“页”(通常是4KB),并以此为基本单位进行管理。 提供连续内存:许多硬件设备(特别是进行直接内存访问DMA的设备)和某些内核数据结构要求得到的内存块在物理上是连续的。伙伴系统的设计目标之一就是能够分配不同大小的、物理连续的内存块。 对抗外部碎片:在长时间运行的系统中,频繁地分配和释放不同大小的内存块会导致物理内存中产生许多不连续的小空闲块。这种现象称为“外部碎片”,它会导致即使总的空闲内存很多,也无法满足一个较大连续内存的申请。伙伴系统通过其独特...
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_...
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...
swap
[TOC] mm/swap.c 交换机制(Swap Mechanism) 物理内存的虚拟扩展历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术以及其实现的交换(Swap)机制,是为了解决一个自计算机诞生以来就存在的根本性限制:物理内存(RAM)的大小是有限的。 运行大于物理内存的程序:在早期,如果一个程序需要比机器拥有的RAM更多的内存,它根本无法运行。交换机制通过将内存中不常用的部分临时存放到磁盘上,从而“欺骗”程序,让它以为自己拥有一个远大于实际物理内存的地址空间。这使得运行大型应用程序成为可能。 同时运行更多的程序:即使每个程序都能装入内存,但同时运行多个程序可能会迅速耗尽RAM。交换机制允许内核将处于空闲或等待状态的进程的内存换出到磁盘,从而为当前活动的进程腾出宝贵的物理内存,提高系统的并发能力和整体吞吐量。 系统休眠(Hibernation):为了实现休眠到磁盘(Suspend-to-Disk)功能,内核需要一个地方来存储整个系统内存的快照。交换空间(Swap Space)被自然地用作这个存储区域。 它的发展经历了哪些重要的里程碑或版本迭代?...
atomic
[TOC] include/asm-generic/bitops/generic-non-atomic.h generic_test_bit 和 const_test_bit 是两个用于测试位图中某个位是否被设置的函数。它们的实现方式略有不同,主要体现在对 volatile 关键字的使用上。generic_test_bit 函数使用了 volatile 关键字,这意味着它会读取内存中的值,而不是使用寄存器中的缓存值。这对于多线程或中断上下文中的位操作非常重要,因为它确保了读取的是最新的值。const_test_bit 函数则不使用 volatile 关键字,这意味着它可以在编译时进行优化,适用于编译时常量的测试。两者的实现都使用了位操作来确定指定的位是否被设置。这里仅进行了读取操作,没有进行写入操作.所以不需要进行原子操作 generic_test_bit 这里具有volatile会在每次读取时都从内存中读取值,而不是进行优化 1234567891011121314/** * generic_test_bit - 确定是否设置了位 * @n...
bits
[toc] include/linux/bits.hBIT_WORD 位图的字数12345678//include/asm-generic/bitsperlong.h#ifdef CONFIG_64BIT#define BITS_PER_LONG 64#else#define BITS_PER_LONG 32#endif /* CONFIG_64BIT */#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) include/linux/bitmap.hbitmap_weight 位图的权重 用于计算位图(bitmap)中设置为 1 的位的数量(即权重) 1234567static __always_inlineunsigned int bitmap_weight(const unsigned long *src, unsigned int nbits){ if (small_const_nbits(nbits)) return hweight_long(*src & BIT...
hashtable
[TOC] include/linux/hashtable.hDEFINE_HASHTABLE 定义哈希表123#define DEFINE_HASHTABLE(name, bits) \ struct hlist_head name[1 << (bits)] = \ { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } hlist_for_each_entry 遍历哈希表12345678910111213141516171819202122232425262728293031323334#define hlist_entry(ptr, type, member) container_of(ptr,type,member)#define hlist_for_each(pos, head) \ for (pos = (head)->first; pos ; pos = pos->next)#define hlist_for_each...








