NTOSKRNL 内存管理器(MM)分析

NTOSKRNL 内存管理器(MM)分析

概述

ReactOS 内核的内存管理器(Memory Manager,简称 MM)位于ntoskrnl\mm\目录。它由两套子系统组成:

  • 旧版 MMntoskrnl\mm\*.c,根目录):ReactOS 早期实现的独立内存管理器
  • ARM3 MMntoskrnl\mm\ARM3\*.c):后来引入的、对齐 Windows NT 架构的新内存管理器,目前是主力实现

两套子系统并存,部分功能由 ARM3 覆盖,部分仍由旧版提供。架构相关代码分离在i386/amd64/arm/子目录中。


1. 目录文件清单与作用

1.1 根目录文件(Legacy / 旧版 MM)

文件功能
[balance.c](file:///d:/reactos/ntoskrnl/mm/balance.c)内存平衡器— 后台内核线程周期性修剪各内存消费者的页面,回收物理页面到空闲列表。MmTrimUserMemory遍历用户 LRU 链表进行换出。
[freelist.c](file:///d:/reactos/ntoskrnl/mm/freelist.c)空闲页面链表与统计— 管理 PFN 数据库、MmAvailablePagesMmTotalCommittedPages等全局物理内存账本。
[marea.c](file:///d:/reactos/ntoskrnl/mm/marea.c)内存区域管理— 虚拟地址区域(VAD)的创建、插入 AVL 树、删除。提供MmCreateMemoryArea/MmInsertMemoryArea/MmFreeMemoryArea
[mmfault.c](file:///d:/reactos/ntoskrnl/mm/mmapfault.c)缺页异常处理(旧版) —MmAccessFault根据错误码分派到MmNotPresentFault等处理程序。
[mminit.c](file:///d:/reactos/ntoskrnl/mm/mminit.c)内存管理器初始化(旧版) —MmInitSystem分 Phase0/Phase1 两阶段执行,建立内核地址空间和系统内存区域。
[pagefile.c](file:///d:/reactos/ntoskrnl/mm/pagefile.c)页面文件管理— 交换文件的读写 I/O、交换槽位的分配/释放。MmWriteToSwapPage/MmReadFromSwapPage
[region.c](file:///d:/reactos/ntoskrnl/mm/region.c)区域子划分— 在内存区域内进一步划分子区域,支持按地址范围修改属性和查找。
[rmap.c](file:///d:/reactos/ntoskrnl/mm/rmap.c)反向映射— 通过物理页面找到所有映射到它的虚拟地址。页面换出的关键前置步骤。
[section.c](file:///d:/reactos/ntoskrnl/mm/section.c)段对象(旧版) — 内存映射文件(Section)的创建、视图映射/取消映射。
[shutdown.c](file:///d:/reactos/ntoskrnl/mm/shutdown.c)关闭清理— 系统关闭时释放页面文件资源、同步脏页面。

1.2 ARM3 子系统(ARM3/目录)

ARM3 是当前的主力内存管理器实现,采用分层架构,各文件职责如下:

初始化与基础设施
文件功能
[mminit.c](file:///d:/reactos/ntoskrnl/mm/ARM3/mminit.c)ARM3 初始化核心MmArmInitSystem两阶段初始化。扫描 LoaderBlock 内存描述符、构建 PFN 数据库、映射 PFN 数据库、构建分页池、初始化颜色表、内存事件等。
[miarm.h](file:///d:/reactos/ntoskrnl/mm/ARM3/miarm.h)主头文件— 核心数据结构定义、宏(页面大小、PTE/PD 尺寸、最低 VAD 地址等)。
[miavl.h](file:///d:/reactos/ntoskrnl/mm/ARM3/miavl.h)AVL 树头文件— VAD 节点专用的 AVL 树算法宏和类型映射。
[sysldr.c](file:///d:/reactos/ntoskrnl/mm/ARM3/sysldr.c)系统镜像加载器(~3600行)— PE 文件的加载/卸载、导入表解析、Thunk 修正、已加载模块链表管理、驱动程序可分页性控制。
[procsup.c](file:///d:/reactos/ntoskrnl/mm/ARM3/procsup.c)进程内存空间管理— PEB/TEB 创建删除、内核栈管理、进程地址空间创建/清理/删除、AWE(Address Windowing Extensions)支持。
物理内存管理
文件功能
[pfnlist.c](file:///d:/reactos/ntoskrnl/mm/ARM3/pfnlist.c)PFN 列表操作— 页面在空闲/备用/已修改/置零列表间的移动、按颜色分配、引用计数/共享计数管理、页面清零。
[freelist.c](file:///d:/reactos/ntoskrnl/mm/freelist.c)空闲页管理(旧版)— 提供全局物理页统计(旧版 MM 仍在使用)。
[zeropage.c](file:///d:/reactos/ntoskrnl/mm/ARM3/zeropage.c)零页线程MiZeroPageThread后台线程将已释放页面清零,维护零页列表供应。
[contmem.c](file:///d:/reactos/ntoskrnl/mm/ARM3/contmem.c)连续内存分配MmAllocateContiguousMemorySpecifyCache等 API,按最低/最高地址、边界对齐分配连续物理页。
[dynamic.c](file:///d:/reactos/ntoskrnl/mm/ARM3/dynamic.c)动态物理内存— 热插拔内存支持(MmAddPhysicalMemory等),大部分尚未实现。
[largepag.c](file:///d:/reactos/ntoskrnl/mm/ARM3/largepag.c)大页面支持— 2MB/4MB 页面分配、大页面范围管理、驱动大页面列表。
虚拟内存管理
文件功能
[virtual.c](file:///d:/reactos/ntoskrnl/mm/ARM3/virtual.c)虚拟内存核心(最大文件之一)—NtAllocateVirtualMemory/NtFreeVirtualMemory/NtProtectVirtualMemory/NtQueryVirtualMemory、跨进程内存复制、物理地址↔虚拟地址转换、安全虚拟内存、写时监视。
[vadnode.c](file:///d:/reactos/ntoskrnl/mm/ARM3/vadnode.c)VAD 树算法— AVL 树插入/删除/查找、空闲地址范围搜索、冲突检查。
[syspte.c](file:///d:/reactos/ntoskrnl/mm/ARM3/syspte.c)系统 PTE 分配器— 系统 PTE 的预留/分配/释放/初始化,支持对齐分配。
[hypermap.c](file:///d:/reactos/ntoskrnl/mm/ARM3/hypermap.c)超空间映射— 物理页面的临时虚拟映射(MiMapPageInHyperSpace/MiUnmapPageInHyperSpace),用于 MM 内部操作。
页面错误与工作集
文件功能
[pagfault.c](file:///d:/reactos/ntoskrnl/mm/ARM3/pagfault.c)页面错误处理(ARM3)—MmArmAccessFault入口、分派到 Demand Zero / PageFile / Transition / Proto PTE 各子处理、栈溢出检查、访问权限检查。
[wslist.cpp](file:///d:/reactos/ntoskrnl/mm/ARM3/wslist.cpp)工作集列表管理— 进程工作集初始化、插入/移除页面、工作集管理器线程(MmWorkingSetManager)修剪逻辑。唯一 C++ 文件。
[balance.c](file:///d:/reactos/ntoskrnl/mm/balance.c)内存平衡器(旧版)— 页面回收的后台线程。
池分配器
文件功能
[expool.c](file:///d:/reactos/ntoskrnl/mm/ARM3/expool.c)Executive 池分配器ExAllocatePoolWithTag/ExFreePoolWithTag、分页池/非分页池管理、大页表管理、池标签跟踪、热标签缓存、验证检查、配额管理。
[pool.c](file:///d:/reactos/ntoskrnl/mm/ARM3/pool.c)池分配器底层页面管理— 池物理页面的分配/释放、非分页池初始化、已释放池页面保护、配额提升/归还。
[special.c](file:///d:/reactos/ntoskrnl/mm/ARM3/special.c)特殊池(Driver Verifier)— 带填充模式的分配/释放、越界访问和 Use-After-Free 检测。
[ncache.c](file:///d:/reactos/ntoskrnl/mm/ARM3/ncache.c)非缓存内存分配MmAllocateNonCachedMemory/MmFreeNonCachedMemory
Section(段对象)与 Session
文件功能
[section.c](file:///d:/reactos/ntoskrnl/mm/ARM3/section.c)Section 对象(ARM3,~3500行)—NtCreateSection/NtMapViewOfSection、数据文件和分页文件映射、系统空间/会话空间视图管理、Segment 生命周期。
[session.c](file:///d:/reactos/ntoskrnl/mm/ARM3/session.c)Session 内存管理— Session 创建/删除/附加/分离、Session ID 位图管理、引用计数。
I/O 与调试支持
文件功能
[iosup.c](file:///d:/reactos/ntoskrnl/mm/ARM3/iosup.c)I/O 空间映射MmMapIoSpace/MmUnmapIoSpace、显示帧缓冲映射、平台缓存属性表。
[mdlsup.c](file:///d:/reactos/ntoskrnl/mm/ARM3/mdlsup.c)MDL 管理— MDL 创建/大小计算/页面分配释放/锁定/缓存指定/预取/保护。
[kdbg.c](file:///d:/reactos/ntoskrnl/mm/ARM3/kdbg.c)调试器支持— Pool 使用统计查询等 KD 扩展。
[mmdbg.c](file:///d:/reactos/ntoskrnl/mm/ARM3/mmdbg.c)内存调试— 物理地址翻译、安全内存复制供内核调试器使用。
[drvmgmt.c](file:///d:/reactos/ntoskrnl/mm/ARM3/drvmgmt.c)驱动管理— 可分页驱动节锁定/解锁、Driver Verifier 支持。
[mmsup.c](file:///d:/reactos/ntoskrnl/mm/ARM3/mmsup.c)杂项支持例程— 地址有效性检查、工作集大小调整、递归 I/O 故障检测、系统大小查询。

1.3 架构相关文件

文件架构功能
[i386/init.c](file:///d:/reactos/ntoskrnl/mm/ARM3/i386/init.c)x86-32 / ARM3定义 x86 模板 PTE/PDE(ValidKernelPde/Pte、DemandZeroPde)、MiInitMachineDependent
[i386/page.c](file:///d:/reactos/ntoskrnl/mm/i386/page.c)x86-32 / ARM3核心页管理:映射创建/删除/查询、保护掩码表、PTE/PDE 操作、页面文件映射管理
[i386/pagepae.c](file:///d:/reactos/ntoskrnl/mm/i386/pagepae.c)x86-32 PAE(旧版)PAE 模式页管理:TLB 刷新、进程地址空间创建(7页 vs 2页)、页表分配/释放
[i386/procsup.c](file:///d:/reactos/ntoskrnl/mm/ARM3/i386/procsup.c)x86-32 / ARM3MiArchCreateProcessAddressSpace— 创建进程地址空间(2级页表、自映射 PDE 技巧)
[amd64/init.c](file:///d:/reactos/ntoskrnl/mm/amd64/init.c)x86-64 / ARM3MiInitMachineDependent— 定义 amd64 模板 PTE/PDE、初始化非分页池和系统 PTE 空间、构建 PFN 数据库(4级页表:PML4→PDPT→PD→PT)
[amd64/procsup.c](file:///d:/reactos/ntoskrnl/mm/amd64/procsup.c)x86-64 / ARM3MiArchCreateProcessAddressSpace— 创建 amd64 进程地址空间(4级页表配置、自映射 PML4)
[arm/init.c](file:///d:/reactos/ntoskrnl/mm/ARM3/arm/init.c)ARM / ARM3MiInitMachineDependent— 初始化非分页池大小和系统内存布局边界
[arm/page.c](file:///d:/reactos/ntoskrnl/mm/arm/page.c)ARM保护掩码表 + 大部分为 UNIMPLEMENTED 存根
[arm/stubs.c](file:///d:/reactos/ntoskrnl/mm/arm/stubs.c)ARM页表辅助函数,部分实现

2. 内存管理流程图

2.1 系统启动初始化流程

Phase0 初始化(MmArmInitSystem Phase=0) │ ├─ MiScanMemoryDescriptors() │ 从 LoaderBlock->MemoryDescriptorList 读取物理内存布局 │ 分类:可用 RAM、XIP ROM、坏块、固件保留等 │ ├─ MiComputeColorInformation() │ 计算 Cache Color(L2 Cache 大小 / 页面大小) │ 初始化颜色表 MiInitializeColorTables() │ ├─ MiBuildPfnDatabase() │ 为每个物理页创建 PFN 条目(约 24 字节/页) │ → 非分页池中为 PFN 数据库预留空间 │ ├─ MiMapPfnDatabase() │ 将 PFN 数据库映射到虚拟地址空间 │ ├─ 初始化系统 PTE 空间(MiInitializeSystemPtes / MiReserveSystemPtes) │ ├─ MiBuildPagedPool() / MiInitializeNonPagedPool() │ 构建分页池和非分页池 │ ├─ MiInitializeMemoryEvents() │ 初始化低内存/高内存事件 │ └─ 初始化工作集管理器参数(MiAdjustWorkingSetManagerParameters) Phase1 初始化(MmArmInitSystem Phase=1) │ ├─ MmInitSystem(旧版 MM 的 Phase1 初始化) │ ├─ MiInitializeLoadedModuleList() │ 建立已加载模块链表,记录所有内核驱动和 DLL │ ├─ MiReloadBootLoadedDrivers() │ 重新处理引导时加载的驱动导入表 │ ├─ MiBuildImportsForBootDrivers() │ 构建导入表解析 │ ├─ MiInitializeLargePageSupport() │ 初始化大页面分配支持 │ ├─ MiInitializeSpecialPool() │ 初始化 Driver Verifier 特殊池 │ └─ MmInitBsmThread() 初始化后台交换元数据线程

2.2 缺页异常处理流程

CPU 触发 Page Fault(CR2 = 故障地址) │ ▼ KiTrap0E(x86 缺页中断处理程序) │ ▼ MmAccessFault (旧版) / MmArmAccessFault (ARM3) │ ├─ 确定故障类型(错误码分析) │ ├─ 页面不存在(位0=0) │ ├─ 写操作违规(位1=1) │ ├─ 用户模式(位2=0) │ └─ 保留位违规(位3=1) │ ├─ MiCheckForUserStackOverflow() │ 检查是否为用户栈溢出 → 自动扩展栈 VAD │ ├─ MiDispatchFault() │ │ │ ├─ MiResolveDemandZeroFault() │ │ 请求置零故障:分配一个零页并映射 │ │ → 调用 MiRemoveZeroPage() 从零页列表取页 │ │ → 若空则从空闲列表取页并调用 MiZeroPhysicalPage() │ │ → 初始化 PFN 条目 │ │ → 填写 PTE │ │ │ ├─ MiResolvePageFileFault() │ │ 页面文件故障:从交换文件读回页面 │ │ → 解析 PTE 中的交换条目(页面文件号 + 槽位偏移) │ │ → MmReadFromSwapPage() → 发起磁盘 I/O │ │ → 等待 I/O 完成 │ │ → 将页面映射到虚拟地址 │ │ │ ├─ MiResolveTransitionFault() │ │ 转换故障:页面在备用/已修改列表中 │ │ → 从列表中移除 │ │ → 重新映射并更新 PFN 状态 │ │ │ ├─ MiResolveProtoPteFault() │ │ 原型 PTE 故障:多个进程共享的映射 │ │ → 复制原型 PTE │ │ → 若需写时复制(COW),分配新页面并复制内容 │ │ → 更新共享计数的 PFN │ │ │ └─ MiCompleteProtoPteFault() │ 完成原型 PTE 故障的后续处理 │ ├─ MiAccessCheck() │ 检查访问权限(读/写/执行) │ └─ 返回 STATUS_SUCCESS 或 引发访问违规异常

2.3 虚拟内存分配流程(NtAllocateVirtualMemory)

NtAllocateVirtualMemory(ProcessHandle, BaseAddress, ZeroBits, Size, AllocationType, Protect) │ ├─ 参数验证(大小对齐、保护标志合法性) │ ├─ MmCheckForContiguousMemory() — 特殊池检查 │ ├─ 锁定工作集锁(WorkingSetLock → AddressSpaceLock) │ ├─ 查找空闲地址范围 │ MiFindEmptyAddressRangeInTree() │ → 遍历 VAD AVL 树,查找满足大小和对齐的空闲区间 │ ├─ 预留(MEM_RESERVE) │ MiInsertVad() │ → 创建 VAD 节点(记录起始地址、大小、保护属性) │ → 插入进程的 VAD AVL 树 │ ├─ 提交(MEM_COMMIT) │ MiCommitPages() │ → 预留系统 PTE(如需要) │ → 更新已提交页面计数(MmTotalCommittedPages) │ → 创建或更新页表项(填写 DemandZero PTE) │ ├─ 释放工作集锁 │ └─ 返回 STATUS_SUCCESS

2.4 页面回收流程(内存平衡器)

内存压力触发(MmAvailablePages 低于阈值) │ ▼ MmRebalanceMemoryConsumers() │ ▼ MiBalancerThread(平衡器内核线程主循环) │ └─ 循环: │ ├─ 计算各消费者应修剪的页面数 │ → 根据消费者优先级和目标值分配配额 │ ├─ MiTrimMemoryConsumer(Consumer) │ │ │ ├─ 调消费者注册的 Trim 回调 │ │ → 对用户进程:MmTrimUserMemory(遍历 LRU 链表) │ │ → 对系统缓存:调用缓存的修剪函数 │ │ │ ├─ 对每个被选中的页面: │ │ 1. MiUnlinkPageFromList() — 从工作集列表移除 │ │ 2. MmDeleteVirtualMapping() — 解除虚拟映射 │ │ 3. rmap 操作 — 删除反向映射记录 │ │ 4. MmWriteToSwapPage() — 将脏页写入交换文件 │ │ 5. MiInsertStandbyListAtFront() — 放入备用列表 │ │ │ └─ 更新可用页面计数 │ ├─ MiZeroPageThread(后台零页线程) │ → 从备用列表取页 → 置零 → 放入零页列表 │ └─ 等待内存压力事件或定时唤醒

2.5 池分配器流程

ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag) │ ├─ MmDeterminePoolType() — 确定池类型 │ → 非分页池 / 分页池 / 会话池 / 特殊池 │ ├─ 若为特殊池 → MmAllocateSpecialPool() │ → 分配对齐系统 PTE │ → 在分配区域前后设置填充模式 │ → 返回地址并记录元数据 │ ├─ 若为普通池: │ │ │ ├─ 检查小/中/大页面分配 │ │ → 小(< ~4KB):从池描述符(POOL_DESCRIPTOR)列表分配 │ │ → 中:从位图管理的池页分配 │ │ → 大:调用 MiAllocatePoolPages() 分配整页 │ │ │ ├─ MiAllocatePoolPages() │ │ → 调 MmRequestPageMemoryConsumer() │ │ → 底层调 MiRemoveAnyPage() 或 MiRemoveZeroPage() │ │ → 若失败 → 触发 MiTrimMemoryConsumer() 回收 │ │ → 若仍失败 → 触发 MmRebalanceMemoryConsumers() │ │ │ ├─ 写入池头部(Pool Header),包含标签、大小、前/后填充模式 │ │ │ └─ 返回分配地址(+ Pool Header 大小偏移) │ └─ ExFreePoolWithTag(Ptr) ├─ 检查是否为特殊池 → MmFreeSpecialPool() ├─ 检查填充模式是否被覆盖(越界检测) ├─ MiFreePoolPages() — 释放底层物理页 └─ 更新配额和统计

3. 数据流图

3.1 全局数据结构关系

┌─────────────────────────────────────────────────────────────┐ │ EPROCESS(进程对象) │ │ │ │ VadRoot (AVL 树根) ←────────────────── VAD 节点链表 │ │ ↓ ┌─────────────────┐ │ │ │ VAD 1: 0x00400000-0x00401000 │ StartingVpn │ │ │ │ VAD 2: 0x00402000-0x0040A000 │ EndingVpn │ │ │ │ VAD 3: ..... │ Protection │ │ │ │ │ ControlArea* ──┼──┐ │ │ │ └─────────────────┘ │ │ │ WorkingSetList(工作集页面链表) │ │ │ [PFN1, PFN15, PFN32, ...] │ │ │ │ │ │ DirectoryTableBase(页目录基址 PFN) │ │ └─────────────────────────────────────────────────────────────┘ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ CONTROL_AREA(控制区) │◄─┘ │ Segment(段对象指针) │ │ FilePointer(文件对象指针) ──→ 内存映射文件 │ │ TheaSegment(原型 PTE 数组) │ │ NumberOfSectionReferences / NumberOfMappedViews │ └─────────────────────────────────────────────────────────────┘ │ ┌─────────────────────────────────────────────────────────────┐ │ │ PFN DATABASE(页帧数据库) │ │ │ │ │ │ MmPfnDatabase[PhysicalPageNumber] │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ │ PFN Entry(~24 字节) │ │ │ │ │ ├─ PageFrameIndex(物理页号) │ │ │ │ │ ├─ PteAddress(指向映射此页的 PTE) ─────→ PTE │ │ │ │ │ ├─ ReferenceCount(引用计数) │ │ │ │ │ ├─ ShareCount(共享计数) │ │ │ │ │ ├─ Flags(页面状态:Modified/Dirty/Accessed/...) │ │ │ │ │ └─ ListEntry(指向所在列表:Free/Standby/Mod/Zero)│ │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ │ 页面列表链: │ │ │ FreeList[color] ←→ StandbyList[color] ←→ ModifiedList │ │ │ ↕ │ │ │ ZeroedList[color] │ │ └─────────────────────────────────────────────────────────────┘ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ PTE(页表项 — 硬件页表) │ │ │ │ │ │ 有效 PTE: │ │ │ ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬──────────────────────────────────┐ │ │ │ │V│R│U│W│C│A│D│L│G│N│ PageFrameNumber │ │ │ │ └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴──────────────────────────────────┘ │ │ │ 交换 PTE: │ │ │ ┌─┬──────────────────────────────────────────────────────┐ │ │ │ │0│ PageFileNumber │ SwapSlotOffset │ │ │ │ └─┴──────────────────────────────────────────────────────┘ │ │ │ 原型 PTE: │ │ │ ┌─┬──────────────────────────────────────────────────────┐ │ │ │ │0│ ProtoPteBit │ PageFileNum │ SwapSlotOffset │ │ │ │ └─┴──────────────────────────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────┘ │

3.2 关键数据流向

应用层 │ │ NtAllocateVirtualMemory / NtFreeVirtualMemory / NtProtectVirtualMemory │ NtCreateSection / NtMapViewOfSection ▼ ┌───────────────────────────────────────────────────────────┐ │ virtual.c — 系统调用处理层 │ │ (参数验证、VAD 操作、页表操作) │ └───────────────────┬───────────────────────────────────────┘ │ ▼ ┌───────────────────────────────────────────────────────────┐ │ vadnode.c — VAD 树算法 │ │ (AVL 树插入/删除/查找/空闲区间搜索) │ └───────────────────┬───────────────────────────────────────┘ │ ▼ ┌───────────────────────────────────────────────────────────┐ │ pagfault.c — 缺页异常处理 │ │ (DemandZero / PageFile / Transition / ProtoPte) │ └───┬───────────────┬───────────────┬───────────────────────┘ │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ │pfnlist.c │ │ pagefile.c │ │ rmap.c │ │PFN操作 │ │ 交换文件 I/O │ │ 反向映射管理 │ │页面链表 │ │ 槽位分配/释放│ │ 物理→虚拟查找 │ └────┬─────┘ └──────┬───────┘ └──────────────────┘ │ │ ▼ │ ┌──────────────┐ │ │ freelist.c │ │ │ 物理页统计 │ │ └──────────────┘ │ │ ▼ ┌───────────────────────────────────────────────────────────┐ │ balance.c — 内存平衡器 │ │ (回收策略、修剪消费者、工作集管理) │ └───────────────────────────────────────────────────────────┘ 池分配路径: ExAllocatePoolWithTag / ExFreePoolWithTag │ ▼ ┌───────────────────────────────────────────────────────────┐ │ expool.c — Executive 池分配器 │ │ (池描述符、标签跟踪、配额管理、大页表) │ └───────────────────┬───────────────────────────────────────┘ │ ▼ ┌───────────────────────────────────────────────────────────┐ │ pool.c — 池物理页管理 │ │ (MiAllocatePoolPages / MiFreePoolPages / 非分页池初始化) │ └───────────────────┬───────────────────────────────────────┘ │ ▼ ┌───────────────────────────────────────────────────────────┐ │ pfnlist.c — 底层物理页分配 │ │ (MiRemoveAnyPage / MiRemoveZeroPage / MiInsertPageInList) │ └───────────────────────────────────────────────────────────┘ Section 映射路径: NtCreateSection / NtMapViewOfSection │ ▼ ┌───────────────────────────────────────────────────────────┐ │ section.c — Section 对象管理 │ │ (控制区/段创建、视图映射、原型 PTE 管理、系统空间映射) │ └───┬───────────────┬───────────────────────────────────────┘ │ │ ▼ ▼ ┌──────────────┐ ┌──────────────┐ │ vadnode.c │ │ virtual.c │ │ VAD 插入 │ │ PTE 填充 │ └──────────────┘ └──────────────┘ 系统镜像加载路径: MmLoadSystemImage │ ▼ ┌───────────────────────────────────────────────────────────┐ │ sysldr.c — 系统加载器 │ │ (PE 解析、导入表解析、Thunk 修正、安全 Cookie、可分页性) │ └───┬───────────────┬───────────────────────────────────────┘ │ │ ▼ ▼ ┌──────────────┐ ┌──────────────────┐ │ section.c │ │ virtual.c │ │ 创建 Section │ │ 映射镜像视图 │ └──────────────┘ └──────────────────┘

3.3 物理页面生命周期状态机

┌──────────┐ ┌────────→│ Free │←────────┐ │ │ (空闲) │ │ │ └────┬─────┘ │ │ │ 分配 │ 释放 │ ▼ │ │ ┌──────────┐ │ │ │ Active │ │ │ │ (活跃) │ │ │ └────┬─────┘ │ │ │ 被换出 │ │ ▼ │ │ ┌──────────┐ │ │ │ Standby │ │ │ │ (备用) │ │ │ └────┬─────┘ │ │ │ 清零 │ │ ▼ │ │ ┌──────────┐ │ │ │ Zeroed │─────────┘ │ │ (已清零) │ │ └──────────┘ │ │ Active → Modified(页面被修改) │ Modified → Standby(修改写入交换文件后) │ Active → Transition(PFN 被其他进程共享但又暂时释放) │ Transition → Active(再次被引用时) │ └── 可用页面总数 = Free + Zeroed + Standby

4. 文件大小与关键统计

文件估算行数复杂度
ARM3/sysldr.c~3600★★★★★
ARM3/section.c~3500★★★★★
ARM3/virtual.c~3500★★★★★
ARM3/expool.c~2500★★★★
ARM3/pagfault.c~2000★★★★
ARM3/mdlsup.c~2000★★★★
ARM3/procsup.c~1800★★★★
ARM3/pfnlist.c~1500★★★
ARM3/vadnode.c~1200★★★
ARM3/mminit.c~1200★★★
其余文件<1000 各★★

5. 关键设计决策

5.1 ARM3 vs 旧版 MM

  • ARM3:对齐 Windows NT 架构,支持 x86-64、PAE、大页面、AWE 等特性。代码更结构化,复用 Windows 的命名和接口约定。
  • 旧版 MM:ReactOS 原始实现,部分功能(freelist.cbalance.cpagefile.c)仍被 ARM3 调用。
  • 过渡策略:ARM3 逐步覆盖旧版功能。目前 ARM3 提供虚拟内存核心(virtual.c)、池分配器(expool.c)、缺页处理(pagfault.c)、Section(section.c)等主要功能,而旧版的marea.cregion.crmap.c等已有 ARM3 对应版本。

5.2 x86 页表自映射技巧

i386 架构下,ARM3 利用页目录的最后一项指向页目录自身,实现页表的虚拟可寻址性:

PD[1023] → PD 自身物理地址(虚拟地址 PTE_BASE 处可访问页表) PD[1022] → 超空间 PDE(用于临时映射物理页) PD[0..1019] → 进程页表项

这种设计使得内核可以通过PTE_BASE + (index * sizeof(PTE))直接访问任意 PTE,无需切换页目录。

5.3 PFN 数据库的物理页账本

每个物理页对应一个MMPFN条目(~24 字节),包含:

  • 引用计数、共享计数
  • PTE 指针(指向映射到此页的 PTE)
  • 页面列表状态(Free/Standby/Modified/Zeroed/Bad/Transition)
  • 颜色索引(Cache Color)
  • 原始访问位和修改位备份

PFN 数据库本身位于非分页池中,由MmArmInitSystem在 Phase0 构建。


6. 与 Windows NT 的差异

特性Windows NTReactOS
工作集管理器MmWorkingSetManager+KeBalanceSetManagerbalance.c+wslist.cpp(简化实现)
修改写入器MiModifiedPageWriter线程依赖balance.c的回调机制
逻辑预取MmPrefetchPages完整实现mdlsup.c中有基本实现
AWENtAllocateUserPhysicalPages完整ARM3 实现
Session Pool完整支持session.c实现,功能有限
ARM 架构完整大部分为 UNIMPLEMENTED 存根