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...
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“一切皆文件”的设计...
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_...
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_sa...
代码补丁
[TOC] static_call 和 jump_label 的区别及异同点static_call 和 jump_label 都是 Linux 内核中的优化机制,旨在提高性能,减少运行时的分支判断和间接调用开销。尽管它们的目标相似,但它们的实现方式和应用场景有所不同。 相同点 动态修改代码路径: 两者都支持在运行时动态修改代码路径,从而实现功能的启用或禁用。 通过修改指令(代码补丁),避免了传统的条件分支或间接调用的性能开销。 性能优化: 两者都旨在减少分支预测失败或间接调用的开销,适用于性能敏感的代码路径。 运行时灵活性: 两者都允许在运行时动态切换功能或行为,而无需重新编译或重启系统。 代码补丁机制: 两者都依赖于代码补丁(code patching)技术,通过修改内存中的指令来实现动态行为。 不同点 特性 static_call jump_label 主要用途 用于优化函数调用,将间接调用替换为直接调用。 用于动态启用或禁用代码块,优化条件分支判断。 优化的内容 函数调用路径(间接调用 → 直接调用)。 条件分支路径(条件判断 →...
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框架的情况...
amba
[TOC] drivers/amba: Linux的AMBA总线与SoC设备驱动核心drivers/amba 目录是 Linux 内核中用于管理和驱动基于 AMBA (Advanced Microcontroller Bus Architecture) 总线的外设的核心框架。在现代基于 ARM 的片上系统 (SoC) 中,几乎所有的片上外设(如 UART、GPIO、SPI、I2C、定时器等)都挂载在 AMBA 总线上。因此,这个目录是 ARM SoC 平台驱动程序的基石。 一、 历史与背景这项技术是为了解决什么特定问题而诞生的? 在嵌入式系统中,特别是 SoC 中,外设不是像 PCI 或 USB 设备那样可以在运行时动态发现的(即非“热插拔”或“可枚举”的)。它们是静态地集成在芯片上的,其物理地址和中断号在芯片设计时就已经固定。 早期的 Linux 内核通过在 C 代码(board-*.c 文件)中硬编码这些“平台设备”(platform devices)的信息来支持它们。这种方法导致了巨大的问题: 内核与硬件紧密耦合: 每支持一款新的开发板,就需要编写一个新的 b...
dma-buf
[TOC] drivers/dma-buf DMA-BUF (DMA Buffer Sharing) Framework 高效的零拷贝缓冲区共享框架历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术以及其所在的dma-buf子系统,是为了解决现代异构计算系统中一个核心的性能和效率问题:如何在不同的硬件设备(驱动)之间高效地共享内存缓冲区,而无需进行昂贵的数据拷贝。 消除数据拷贝(Zero-Copy):在典型的多媒体处理流程中,一个数据流(如视频帧)可能需要经过多个硬件单元处理:例如,从摄像头控制器捕获,由视频编解码器(CODEC)进行编码/解码,交由GPU进行渲染或后期处理,最后发送到显示控制器进行显示。在没有dma-buf的时代,每一步之间的数据传递通常都需要CPU介入,将数据从一个设备的内存区域拷贝到另一个设备的内存区域,这会消耗大量的CPU周期和内存带宽,是系统性能的主要瓶颈。 统一的共享接口:在dma-buf出现之前,不同的子系统有各自私有的缓冲区共享方式(例如V4L2的USERPTR)。 这导致了接口不统一,无法实现任意设备间的缓冲区共享,...







