ntoskrnl\mm 源码学习与内存管理计划

📅 2026/7/19 23:20:07
ntoskrnl\mm 源码学习与内存管理计划
ntoskrnl\mm 源码学习与内存管理计划概述本计划针对 ReactOS 内核内存管理器ntoskrnl\mm\的源码学习。MM 子系统由旧版 MM根目录 10 个文件和ARM3ARM3/子目录 30 个文件两套实现组成当前主力为 ARM3。整个目录包含约 49 个源文件 多个架构特定实现。第一阶段前置知识准备1.1 硬件分页机制预计 1-2 天在学习任何 MM 源码之前必须先理解 CPU 的分页硬件机制。主题关键概念参考材料x86 32位分页页目录 (PD)、页表 (PT)、PTE 结构、4KB/4MB 页面Intel/AMD 手册 Vol 3PAE 分页页目录指针表 (PDPT)、36位物理地址、64位 PTEIntel/AMD 手册 Vol 3x86-64 分页PML4 → PDPT → PD → PT 四级页表AMD 手册 Vol 2ARM 分页二级页表、段/大页/小页ARM 架构手册TLB 刷新INVEPT、INVVPID、CR3 切换Intel/AMD 手册练习手绘 x86 分页地址转换图虚拟地址 → PDE → PTE → 物理页。1.2 Windows 内存管理概念预计 2-3 天概念说明MM 中对应虚拟地址描述符 (VAD)描述进程地址空间中每个区域的 AVL 树节点vadnode.c,miarm.h页帧号数据库 (PFN DB)每个物理页一个条目记录引用计数、状态、映射pfnlist.c,freelist.c工作集 (Working Set)进程当前在物理内存中的页面集合wslist.cpp,balance.c段对象 (Section)文件与虚拟内存之间的映射抽象section.c(ARM3),section.c(旧版)池 (Pool)内核堆分配器分页/非分页expool.c,pool.c系统 PTE内核虚拟地址空间中的空闲页表项syspte.c超空间 (Hyperspace)临时映射物理页到内核空间的机制hypermap.cMDL描述物理内存缓冲区的数据结构mdlsup.c推荐阅读Windows Internals 7thPart 1 Chapter 9 “Memory Management”。第二阶段源码模块阅读建议顺序2.1 核心头文件 — 建立全局认知[miarm.h](file:///d:/reactos/ntoskrnl/mm/ARM3/miarm.h)地位整个 MM 子系统的唯一核心头文件零外部依赖无#include阅读重点保护常量MM_ZERO_ACCESS到MM_EXECUTE_WRITECOPYPTE 标志位PTE_VALID、PTE_DIRTY、PTE_ACCESSED、PTE_PROTOTYPE、PTE_TRANSITIONPFN 状态ZeroedPageList、FreePageList、StandbyPageList、ModifiedPageList、BadPageList页表自映射区域PTE_BASE、PDE_BASEx86 特有技巧结构体MMPFN、MMPTE、MMVAD、MM_AVL_TABLE目标能闭眼画出 PFN 条目布局和 PTE 各字段含义[miavl.h](file:///d:/reactos/ntoskrnl/mm/ARM3/miavl.h)地位VAD 树专用的 AVL 算法内联实现仅被vadnode.c包含阅读重点理解从 RTL 通用 AVL 到 MM 专用类型的宏映射目标理解平衡因子和父指针共用同一字段的优化2.2 初始化子系统 — 理解启动流程[ARM3/mminit.c](file:///d:/reactos/ntoskrnl/mm/ARM3/mminit.c)函数MmArmInitSystem阅读重点Phase0 初始化扫描内存描述符 → 构建 PFN 数据库 → 映射 PFN DB → 构建分页池 → 初始化颜色表Phase1 初始化已加载模块链表 → 大页面支持 → 特殊池 → 后台交换线程非分页池大小计算算法配合阅读[mminit.c旧版](file:///d:/reactos/ntoskrnl/mm/mminit.c) 了解MmInitSystem[amd64/init.c](file:///d:/reactos/ntoskrnl/mm/amd64/init.c) / [i386/init.c](file:///d:/reactos/ntoskrnl/mm/ARM3/i386/init.c)函数MiInitMachineDependent阅读重点架构相关的模板 PTE/PDE 定义、页表层次映射2.3 物理内存管理 — 页帧与分配器[pfnlist.c](file:///d:/reactos/ntoskrnl/mm/ARM3/pfnlist.c)核心函数MiRemoveAnyPage、MiRemoveZeroPage、MiInsertPageInList、MiInitializePfn阅读重点物理页的六种状态Active / Transition / Standby / Modified / Free / Zeroed / Bad按颜色分配算法 (Cache Color)引用计数和共享计数的增减逻辑流程图绘制物理页生命周期状态机[freelist.c](file:///d:/reactos/ntoskrnl/mm/freelist.c)阅读重点全局统计变量MmAvailablePages、MmTotalCommittedPages、MmPfnDatabase[zeropage.c](file:///d:/reactos/ntoskrnl/mm/ARM3/zeropage.c)核心函数MiZeroPageThread阅读重点后台零页线程的工作循环从备用列表取页 → 置零 → 放入零页列表[contmem.c](file:///d:/reactos/ntoskrnl/mm/ARM3/contmem.c) / [largepag.c](file:///d:/reactos/ntoskrnl/mm/ARM3/largepag.c)阅读重点MmAllocateContiguousMemorySpecifyCache的完整分配路径理解大页面的分配条件和对性能的影响2.4 虚拟内存管理 — VAD 与系统调用[vadnode.c](file:///d:/reactos/ntoskrnl/mm/ARM3/vadnode.c)核心函数MiLocateVad、MiInsertVad、MiRemoveNode、MiFindEmptyAddressRangeInTree阅读重点在 AVL 树中查找包含指定地址的 VAD 的算法练习手写MiLocateVad的二叉树搜索过程[virtual.c](file:///d:/reactos/ntoskrnl/mm/ARM3/virtual.c)核心函数NtAllocateVirtualMemory、NtFreeVirtualMemory、NtProtectVirtualMemory、NtQueryVirtualMemory阅读重点按顺序NtAllocateVirtualMemory完整路径参数验证 → 锁定工作集锁 → 找空闲区间 → 插 VAD → 提交页面NtFreeVirtualMemory路径释放 VAD → 删除 PTE → 释放物理页 → 更新 PFNMmGetPhysicalAddress虚拟地址 → 物理地址转换MiDeletePte和MiDeleteVirtualAddresses反向操作的底层逻辑数据流画出 NtAllocateVirtualMemory 的完整函数调用链[syspte.c](file:///d:/reactos/ntoskrnl/mm/ARM3/syspte.c)核心函数MiReserveSystemPtes、MiReleaseSystemPtes阅读重点系统 PTE 的位图分配算法2.5 缺页异常处理 — 核心性能路径[pagfault.c](file:///d:/reactos/ntoskrnl/mm/ARM3/pagfault.c)核心函数MmArmAccessFault→MiDispatchFault四种故障类型按重要性排序MiResolveDemandZeroFault— 请求零页分配 → 置零 → 映射MiResolvePageFileFault— 页文件换回解析 PTE 交换条目 → 磁盘 I/O 读回MiResolveTransitionFault— 转换故障备用/已修改列表中的页重新激活MiResolveProtoPteFault— 原型 PTE 故障共享页的写时复制 (COW)阅读重点错误码分析PF 错误码各位含义MiCheckForUserStackOverflow— 用户栈自动扩展MiAccessCheck— 访问权限验证配合阅读[i386/page.c](file:///d:/reactos/ntoskrnl/mm/i386/page.c) 中页表操作底层函数2.6 池分配器 — 内核堆[expool.c](file:///d:/reactos/ntoskrnl/mm/ARM3/expool.c) [pool.c](file:///d:/reactos/ntoskrnl/mm/ARM3/pool.c)核心函数ExAllocatePoolWithTag、ExFreePoolWithTag阅读重点三种分配粒度小POOL_DESCRIPTOR 列表、中位图管理页、大整页池头部结构和标签跟踪机制热标签缓存 (Hot Tags)配额管理MmRaisePoolQuota/MmReturnPoolQuota非分页池初始化流程配合阅读[special.c](file:///d:/reactos/ntoskrnl/mm/ARM3/special.c) 了解 Driver Verifier 特殊池的填充模式检测2.7 段对象与文件映射[section.cARM3](file:///d:/reactos/ntoskrnl/mm/ARM3/section.c)核心函数NtCreateSection、NtMapViewOfSection阅读重点数据文件映射MiCreateDataFileMapvs 分页文件映射MiCreatePagingFileMap控制区 (Control Area) → 段 (Segment) → 原型 PTE (Prototype PTE) 的层次关系系统空间映射MiMapViewInSystemSpace配合阅读[mdlsup.c](file:///d:/reactos/ntoskrnl/mm/ARM3/mdlsup.c) 了解 MDL 创建和页面锁定2.8 进程与会话[procsup.c](file:///d:/reactos/ntoskrnl/mm/ARM3/procsup.c)核心函数MmCreateProcessAddressSpace、MmCleanProcessAddressSpace、MmDeleteProcessAddressSpace阅读重点进程地址空间创建的完整步骤配合阅读[i386/procsup.c](file:///d:/reactos/ntoskrnl/mm/ARM3/i386/procsup.c) / [amd64/procsup.c](file:///d:/reactos/ntoskrnl/mm/amd64/procsup.c) 理解架构差异[session.c](file:///d:/reactos/ntoskrnl/mm/ARM3/session.c)阅读重点MmSessionCreate/MmSessionDelete、Session ID 位图管理2.9 工作集与内存平衡[wslist.cpp](file:///d:/reactos/ntoskrnl/mm/ARM3/wslist.cpp)核心函数MmWorkingSetManager、MiInsertInWorkingSetList、MiRemoveFromWorkingSetList注意这是 MM 目录中唯一的 C 文件[balance.c](file:///d:/reactos/ntoskrnl/mm/balance.c)核心函数MiBalancerThread、MmTrimUserMemory、MmRebalanceMemoryConsumers阅读重点页面回收的完整路径消费者注册和优先级Trim 回调调用解除映射 → 写交换文件 → 放入备用列表2.10 页面文件与反向映射[pagefile.c](file:///d:/reactos/ntoskrnl/mm/pagefile.c)旧版未适配 ARM3核心函数MmWriteToSwapPage、MmReadFromSwapPage、MmAllocSwapPage、MmFreeSwapPage阅读重点交换槽位分配和磁盘 I/O 发起的完整路径[rmap.c](file:///d:/reactos/ntoskrnl/mm/rmap.c)旧版阅读重点反向映射如何支持页面换出2.11 系统镜像加载[sysldr.c](file:///d:/reactos/ntoskrnl/mm/ARM3/sysldr.c)核心函数MmLoadSystemImage、MmUnloadSystemImage阅读重点PE 文件的加载过程导入表解析MiResolveImageReferencesThunk 修正MiSnapThunk驱动程序可分页性控制MmPageEntireDriver/MmResetDriverPaging第三阶段深入理解与验证练习3.1 代码阅读练习练习目标文件要求画出页表自映射结构i386/procsup.c解释 PD[1023]→PD、PTE_BASE 寻址原理追踪页分配路径pfnlist.c→virtual.c从NtAllocateVirtualMemory到物理页的完整链画出 PFN 状态机pfnlist.cfreelist.c包含所有 6 种状态的转换条件和触发函数分析写时复制pagfault.c→MiResolveProtoPteFault写出 COW 的触发条件和页面分配逻辑池分配链路expool.c→pool.c→pfnlist.c从ExAllocatePoolWithTag到物理页的完整链缺页异常完整路径pagfault.c画出 CPU 异常 → 内核分发 → 各子处理器的分派树工作集修剪过程balance.cwslist.cpp从内存压力触发到页面回收的完整路径3.2 编译调试练习练习操作验证方法添加 DPRINT1 日志在关键路径入口添加日志查看串口输出确认调用路径触发缺页异常运行测试程序访问未提交内存串口观察MiDispatchFault日志监控池分配在ExAllocatePoolWithTag添加跟踪查看分配模式和标签触发页面回收运行大内存消耗程序观察MiBalancerThread活动3.3 阅读路线图┌─────────────────────────────────────────────────────────────────┐ │ 推荐阅读顺序 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 1. miarm.h miavl.h ← 头文件基础1天 │ │ ↓ │ │ 2. mminit.c ← 初始化流程1天 │ │ ↓ │ │ 3. pfnlist.c freelist.c ← 物理页管理1-2天 │ │ ↓ │ │ 4. vadnode.c ← VAD 树算法1天 │ │ ↓ │ │ 5. virtual.c ← 虚拟内存核心2天 │ │ ↓ │ │ 6. pagfault.c i386/page.c ← 缺页处理2天 │ │ ↓ │ │ 7. expool.c pool.c ← 池分配器1-2天 │ │ ↓ │ │ 8. section.cARM3 ← 段对象2天 │ │ ↓ │ │ 9. procsup.c session.c ← 进程/会话1天 │ │ ↓ │ │ 10. wslist.cpp balance.c ← 工作集1-2天 │ │ ↓ │ │ 11. pagefile.c rmap.c ← 页文件/反向映射1天 │ │ ↓ │ │ 12. sysldr.c ← 系统加载器2天 │ │ ↓ │ │ 13. mdlsup.c iosup.c ← MDL/I/O 支持1天 │ │ ↓ │ │ 14. 架构文件i386/amd64等 ← 架构差异1天 │ │ │ │ 总计约 17-22 天 │ └─────────────────────────────────────────────────────────────────┘第四阶段推荐学习资料书籍Windows Internals, 7th Edition— Part 1, Chapter 9 “Memory Management”这是理解 Windows 内存管理架构的最佳参考Understanding the Linux Kernel, 3rd Edition— Chapter 8 “Memory Management”与 Linux 对比学习有助于加深理解Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A分页机制硬件细节在线资源ReactOS 官方 Wiki — Memory ManagerWindows内核原理与实现潘爱民 — 中文经典WRK (Windows Research Kernel) 源码 — 对照参考ReactOS 内部文档doc/ARM3内存管理器分析.md— 已有的 ARM3 分析文档doc/MM实现分析.md— 旧版 MM 的实现分析doc/ntoskrnl内存管理器MM分析.md— 综合分析已有第五阶段学习验证清单每节完成后自测能画出 x86 两级分页地址转换图能解释 PAE 和非 PAE 的区别能写出 x86-64 四级页表的各级名称能画出 PFN 条目结构和页面状态机能描述 VAD AVL 树的搜索算法能写出NtAllocateVirtualMemory的完整调用链能解释四种缺页故障类型及处理方式能描述池分配器的小/中/大三级分配策略能画出 Section 对象 → 控制区 → 段 → 原型 PTE 的层次能解释页表自映射技巧的原理能描述页面回收的完整路径平衡器 → 修剪 → 换出能解释逆向映射的作用和工作原理能描述 PE 镜像加载过程的关键步骤代码修改练习在某个关键路径上添加 DPRINT1 并验证串口输出找到一处UNIMPLEMENTED或存根函数并实现它给某个复杂函数添加中文注释解释