Linux内核分析之内存管理-07
第7章:页面分配
基于 Linux 6.12.38 源码
7.1 页面分配概述
7.1.1 分配层次
Linux 内核提供了多种内存分配方式,适用于不同的场景:
1 | ┌─────────────────────────────────────────────────────────────┐ |
7.1.2 用户空间内存分配完整调用链
1 | ┌─────────────────────────────────────────────────────────────────────┐ |
7.1.3 分配 API 分类
| 类型 | API | 单位 | 用途 |
|---|---|---|---|
| 物理页面 | alloc_pages() |
页 (4KB) | 物理内存分配 |
| 虚拟地址 | __get_free_pages() |
页 (4KB) | 直接映射区虚拟地址 |
| 字节 | kmalloc() |
字节 | 小对象分配 |
| 非连续 | vmalloc() |
字节 | 非连续虚拟内存 |
| 精确 | alloc_pages_exact() |
字节 | 精确大小分配 |
7.2 alloc_pages 函数族
7.2.1 核心分配函数
位置: include/linux/gfp.h
1 | /* 分配 2^order 个连续页面,返回 struct page */ |
7.2.2 从 VMA 分配
1 | /* 从 VMA 分配页面 (考虑 VMA 策略) */ |
7.2.3 使用示例
1 | /* 分配单页 */ |
7.3 __get_free_pages 函数族
7.3.1 函数定义
1 | /* 分配页面并返回内核虚拟地址 */ |
7.3.2 使用示例
1 | /* 分配一个页面,返回虚拟地址 */ |
7.3.3 与 alloc_pages 的区别
| 特性 | alloc_pages() |
__get_free_pages() |
|---|---|---|
| 返回类型 | struct page * |
unsigned long (虚拟地址) |
| 地址范围 | 任意物理内存 | 直接映射区 |
| 高端内存 | 支持 | 仅当启用 CONFIG_HIGHMEM |
| 典型用途 | 需要操作 struct page | 需要直接访问内存 |
7.4 释放页面
7.4.1 释放函数
1 | /* 释放页面 (已知 struct page) */ |
7.4.2 释放流程
1 | __free_pages(page, order=2) |
7.4.3 释放注意事项
1 | /* 不要释放 NULL 页面 */ |
7.5 页面引用计数
7.5.1 引用计数操作
位置: include/linux/page_ref.h
1 | /* 增加引用计数 */ |
7.5.2 引用计数使用
1 | /* 获取页面引用 */ |
7.6 精确分配
7.6.1 alloc_pages_exact
1 | /* 分配指定大小的连续内存 */ |
7.6.2 使用场景
1 | /* 分配 10KB 的连续内存 (非 2^n 次幂) */ |
7.7 批量分配
7.7.1 批量分配 API
1 | /* 批量分配到列表 */ |
7.7.2 批量分配示例
1 | /* 批量分配 128 个页面到数组 */ |
7.8 页面转换
7.8.1 page 和虚拟地址转换
1 | /* page → 虚拟地址 */ |
7.8.2 高端内存映射
1 | /* 临时映射高端内存页面 */ |
7.9 分配跟踪与调试
7.9.1 分配跟踪
1 | /* 分配跟踪钩子 (CONFIG_MEM_ALLOC_PROFILING) */ |
7.9.2 调试选项
1 | CONFIG_DEBUG_PAGEALLOC # 调试页面分配 |
7.9.3 调试函数
1 | /* 检查页面是否保留 */ |
7.10 本章小结与跨章节关联
7.10.1 本章要点
本章介绍了 Linux 6.12 的页面分配:
- 分配层次: kmalloc/vmalloc → alloc_pages → Buddy System → 物理页面
- alloc_pages 函数族: 返回 struct page,分配物理页面
- __get_free_pages 函数族: 返回虚拟地址,直接映射区
- 释放页面: __free_pages,伙伴合并
- 引用计数: get_page/put_page,页面生命周期管理
- 精确分配: alloc_pages_exact,非 2^n 次幂分配
- 批量分配: alloc_pages_bulk,提高效率
- 页面转换: page 和虚拟地址互转
- 分配跟踪: 调试选项和函数
7.10.2 与其他章节的关系
1 | ┌────────────────────────────────────────────────────────────┐ |
关键分配路径:
快速路径:
alloc_pages()→per_cpu_pages(PCP缓存) → 直接返回- 相关章节: ch02 (per_cpu_pages结构)
慢速路径 - 低水位:
alloc_pages()→wakeup_kswapd()→kswapd回收- 相关章节: ch02 (watermark), ch10 (kswapd实现)
慢速路径 - 直接回收:
alloc_pages()→__alloc_pages_direct_reclaim()- 相关章节: ch10 (直接回收)
慢速路径 - 压缩:
alloc_pages()→__alloc_pages_direct_compact()- 相关章节: ch13 (内存压缩)
用户空间分配:
malloc()→brk()/mmap()→缺页异常→alloc_pages()- 相关章节: ch09 (缺页处理), ch11 (mmap), ch12 (匿名内存)
下一章将介绍 Slab 分配器。
- Title: Linux内核分析之内存管理-07
- Author: 韩乔落
- Created at : 2026-01-20 21:39:19
- Updated at : 2026-02-24 14:05:13
- Link: https://jelasin.github.io/2026/01/20/Linux内核分析之内存管理-07/
- License: This work is licensed under CC BY-NC-SA 4.0.
Comments