
mm/page_alloc.c是 Linux 内核内存管理子系统中最核心、最庞大的文件之一主要负责物理内存页的分配与释放也就是常说的伙伴系统Buddy System的实现。它是所有物理内存分配如alloc_pages、__get_free_pages、kmalloc的底层的最终落脚点。下面按功能模块梳理它的主要职责1. 伙伴系统Buddy System的核心实现这是该文件最根本的功能管理物理内存的页框page frame以 2 的幂次为单位进行分配和释放。__free_one_page()释放一个页块时检查其伙伴页块是否空闲若空闲则合并成更大的块并递归向上合并。__rmqueue()/__rmqueue_smallest()/__rmqueue_fallback()从空闲链表中摘取合适大小的页块当指定迁移类型migrate type没有空闲块时会从其他迁移类型偷取fallback。expand()当只需要小块但只有大块空闲时把大块逐级分裂成小块。__find_buddy_pfn()通过 PFN 异或运算快速找到伙伴页框。空闲页块按order阶组织在free_area[order]中每个 order 下又按迁移类型MIGRATE_UNMOVABLE / MOVABLE / RECLAIMABLE 等分成多个链表以尽量保持内存的连续性、减少碎片。2. 每 CPU 页框缓存Per-CPU Pages, PCP为了减少对 zone 锁的争用、提高分配速度per_cpu_pages/per_cpu_pageset每个 CPU 每个 zone 维护一个本地页框缓存。rmqueue_pcplist()/rmqueue_bulk()优先从本地缓存分配缓存空了才批量从伙伴系统补充。free_unref_page()/free_pcppages_bulk()释放时先放入本地缓存达到高水位再批量归还伙伴系统。相关水位pcp-high、pcp-batch、pcp-low。这是现代内核分配热路径的关键优化。3. 分配接口对外 API向上层提供多种粒度的物理内存分配函数函数说明alloc_pages()/alloc_pages_node()分配 2^order 个连续物理页返回struct page *__get_free_pages()/__get_free_page()返回虚拟地址的分配get_zeroed_page()分配并清零一页__alloc_pages()/__alloc_pages_noprof()核心分配函数含完整的慢路径__alloc_pages_slowpath()慢路径唤醒 kswapd、直接回收、内存规整、OOM 等__alloc_pages_direct_compact()内存规整compaction__alloc_pages_direct_reclaim()直接回收__alloc_pages_may_oom()触发 OOM killerGFP 标志gfp_t的处理也在这里例如GFP_KERNEL、GFP_ATOMIC、__GFP_ZERO、__GFP_HIGHMEM等决定从哪个 zone 分配、能否睡眠/回收。4. 释放接口free_pages()/__free_pages()释放页块最终调用__free_one_page()。free_unref_page()/free_pages_prepare()释放前的检查与准备如检查 page 引用计数、处理PageAnon、PageDirty等。__put_page()/put_page()减少引用计数归零时释放。5. 内存水位与回收触发zone_watermark_ok()/zone_watermark_fast()检查 zone 是否达到水位WMARK_MIN/LOW/HIGH。__zone_watermark_ok()考虑保留页、迁移类型后的水位判断。wake_all_kswapds()水位不足时唤醒 kswapd 后台回收。should_reclaim_retry()/should_compact_retry()慢路径中的重试策略。6. 内存热插拔与初始化free_area_init()/free_area_init_nodes()初始化每个 node/zone 的free_area、zone结构。build_all_zonelists()构建 zone 的分配顺序列表zonelist。memmap_init()/memmap_init_range()初始化struct page数组。__init_single_page()初始化单个 page 结构。与CONFIG_MEMORY_HOTPLUG相关的online_pages()、offline_pages()也在部分版本中涉及。memblock交互早期内存从 memblock 移交给伙伴系统。7. 内存碎片化与迁移类型MIGRATE_UNMOVABLE / MOVABLE / RECLAIMABLE / RESERVE / ISOLATE / CMA等迁移类型的维护。set_pageblock_migratetype()/get_pageblock_migratetype()设置/获取页块迁移类型。__rmqueue_fallback()防止碎片化的关键逻辑避免破坏大块连续内存。find_suitable_fallback()寻找可回退的迁移类型。与 CMA连续内存分配器、__GFP_CMA的交互。8. 页块隔离与内存规整配合alloc_contig_range()/__alloc_contig_migrate_range()分配连续物理内存用于 CMA、hugetlb 等。isolate_freepages()/isolate_migratepages()部分在compaction.c但入口在 page_alloc 中协调。has_unmovable_pages()/is_pageblock_removable_nolock()判断页块是否可移动/可移除。9. 统计与调试vm_stat//proc/pagetypeinfo//proc/buddyinfo统计各 order、各迁移类型的空闲页数。__count_zone_vm_events()更新 zone 事件计数。bad_page()检测到损坏的 page 时的报错。dump_page()打印 page 信息用于调试。check_new_page()/free_pages_check()调试模式下检查 page 一致性。setup_per_cpu_pageset()初始化每 CPU 页集。10. 与其他模块的接口向SLUB/SLABmm/slub.c提供底层页块。向vmallocmm/vmalloc.c提供页表页和物理页。向页表管理mm/memory.c提供pte_alloc所需的页。与kswapdmm/vmscan.c配合做页面回收。与compactionmm/compaction.c配合减少碎片。与CMAmm/cma.c配合预留连续内存。与memory cgroupmm/memcontrol.c配合做内存统计和限制。总结一句话mm/page_alloc.c是 Linux物理内存页分配器的实现核心负责伙伴系统的分配/释放、每 CPU 缓存、内存水位判断、慢路径回收与规整、迁移类型与反碎片、内存热插拔初始化以及向上层提供alloc_pages/free_pages等基础接口。它是整个内核内存管理的地基。