mm学习笔记_03:物理页管理与PFN数据库

发布时间:2026/7/19 14:01:34
mm学习笔记_03:物理页管理与PFN数据库 mm学习笔记_03物理页管理与PFN数据库基于 ReactOS ARM3 MM 源码ntoskrnl/mm/ARM3/pfnlist.c ntoskrnl/mm/freelist.c1. pfnlist.c 概述文件位置d:\reactos\ntoskrnl\mm\ARM3\pfnlist.c职责管理物理页面的 PFNPage Frame Number数据库操作包括页面在空闲/已清零/备用/已修改等列表间的移动、按缓存颜色分配、引用计数/共享计数管理、页面清零等。核心数据结构——MMPFN条目每个物理页一个typedefstruct_MMPFN{struct{PFN_NUMBER Flink;// 链表前向指针PFN_NUMBER WsIndex;// 工作集索引PVOID Event;// 等待事件PVOID ReadStatus;// 读取状态}u1;struct{PFN_NUMBER Blink;// 链表后向指针SHORT ShareCount;// 共享计数}u2;struct{struct{...}e1;// PageLocation, CacheAttribute, Rom 等标志struct{...}e2;// ReferenceCount, ShortFlags}u3;union{...}u4;// PteFrame, Priority 等PMMPTE PteAddress;// 指向映射到此页的 PTEMMPTE OriginalPte;// 原始 PTE 备份}MMPFN;2. 物理页8种状态及状态转换图在miarm.h中定义typedefenum_MMLISTS{ZeroedPageList0,// 已清零页面可直接使用FreePageList1,// 空闲页面内容未知StandbyPageList2,// 备用页面内容有效但无引用可直接回收ModifiedPageList3,// 已修改页面需写回磁盘后才可回收ModifiedNoWritePageList4,// 已修改但不写回如临时页BadPageList5,// 坏页硬件故障ActiveAndValid6,// 活跃有效正在使用TransitionPage7// 转换中介于有效与无效之间}MMLISTS;状态转换图┌──────────────┐ │ ZeroedPage │◄──────── 零页线程清零 │ (已清零空闲) │ └──────┬───────┘ │ MiRemoveZeroPage() ▼ ┌──────────────┐ ┌─────►│ ActiveAndValid │◄──── MiResolveDemandZeroFault │ │ (活跃有效) │◄──── MiResolvePageFileFault │ └───────┬───────┘◄──── MiResolveTransitionFault │ │ │ │ 页面被替换/释放 │ ▼ │ ┌──────────────┐ │ │ TransitionPage│──► 如果共享计数为0进入对应列表 │ │ (转换中) │ │ └──────┬───────┘ │ │ │ ┌───────┴────────┬──────────┐ │ ▼ ▼ ▼ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │StandbyPage│ │ModifiedPage│ │ModNoWrite│ │ │ (备用) │ │ (已修改) │ │ (不改写) │ │ └─────┬────┘ └─────┬────┘ └──────────┘ │ │ │ │ │ 写回磁盘 │ │ ▼ │ │ ┌──────────┐ │ │ │ Zeroed │◄─────┘ │ │ 零页 │ │ └────┬─────┘ │ │ 清零 │ ▼ │ ┌──────────┐ └──│ FreePage │ │ (空闲) │ └──────────┘关键规律可用页面总和 Free Zeroed Standby即MmAvailablePagesActiveAndValid的页面引用计数 0共享计数 0Transition页面保留了物理内容PTE 被标记为 Transition位 11 1, 位 0 0BadPage从系统初始化时标记永不回收使用3. 关键函数分析3.1 MiRemoveAnyPage——优先空闲页文件pfnlist.c:477功能从物理页列表中取出任意一页优先取空闲页FreePageList其次取已清零页ZeroedPageList。搜索顺序先尝试从MmFreePagesByColor[FreePageList][Color].Flink取按颜色空闲页若空尝试MmFreePagesByColor[ZeroedPageList][Color].Flink按颜色零页若空尝试MmFreePageListHead.Flink全局空闲链表若空尝试MmZeroedPageListHead.Flink全局零页链表PFN_NUMBER NTAPIMiRemoveAnyPage(IN ULONG Color){// 1. 先取对应颜色的空闲页PageIndexMmFreePagesByColor[FreePageList][Color].Flink;if(PageIndexLIST_HEAD){// 2. 取对应颜色的零页PageIndexMmFreePagesByColor[ZeroedPageList][Color].Flink;if(PageIndexLIST_HEAD){// 3. 取全局空闲链表PageIndexMmFreePageListHead.Flink;if(PageIndexLIST_HEAD){// 4. 取全局零页链表PageIndexMmZeroedPageListHead.Flink;}}}// 从对应颜色列表中移除PageIndexMiRemovePageByColor(PageIndex,Color);returnPageIndex;}3.2 MiRemoveZeroPage——优先零页文件pfnlist.c:537功能优先取已清零页仅在零页为空时回退取空闲页并手动清零。PFN_NUMBER NTAPIMiRemoveZeroPage(IN ULONG Color){BOOLEAN ZeroFALSE;// 1. 取颜色零页PageIndexMmFreePagesByColor[ZeroedPageList][Color].Flink;if(PageIndexLIST_HEAD){// 2. 取全局零页链表PageIndexMmZeroedPageListHead.Flink;if(PageIndexLIST_HEAD){ZeroTRUE;// 需要手动清零// 3. 取颜色空闲页PageIndexMmFreePagesByColor[FreePageList][Color].Flink;if(PageIndexLIST_HEAD){// 4. 取全局空闲链表PageIndexMmFreePageListHead.Flink;}}}PageIndexMiRemovePageByColor(PageIndex,Color);if(Zero)MiZeroPhysicalPage(PageIndex);// 手动清零returnPageIndex;}3.3 MiInsertPageInFreeList文件pfnlist.c:611功能将已释放的物理页插回空闲链表尾部同时更新颜色列表。当空闲列表达到 8 页时唤醒零页线程MmZeroingPageEvent。VOID NTAPIMiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex){// 设置链表指针插到尾部LastPageListHead-Blink;Pfn1-u1.FlinkLIST_HEAD;Pfn1-u2.BlinkLastPage;// 设置状态Pfn1-u3.e1.PageLocationFreePageList;Pfn1-u4.Priority3;// 更新颜色列表ColorPageFrameIndexMmSecondaryColorMask;ColorTableMmFreePagesByColor[FreePageList][Color];// ...插入到颜色链表尾部// 递增可用页计数MiIncrementAvailablePages();// 如果空闲页 8唤醒零页线程if(ListHead-Total8)KeSetEvent(MmZeroingPageEvent,IO_NO_INCREMENT,FALSE);}3.4 MiInsertPageInList文件pfnlist.c:779功能通用页面插入函数根据ListHead的ListName决定插入策略ZeroedPageList插入到链表头部最新清零的页在最前面StandbyPageList按优先级插入到MmStandbyPageListByPriority[Priority]ModifiedPageList插入到颜色子链表更新MmTotalPagesForPagingFileModifiedNoWritePageList尚未实现ASSERT(FALSE)4. 颜色分配算法Cache Color作用避免 CPU 缓存颠簸Cache Thrashing将物理页按其在 CPU 缓存中的位置分组优先分配相同颜色的页面给同一进程。核心思想物理地址的某些低位MmSecondaryColorMask决定了该页在 CPU 缓存中的映射位置。当同一进程的连续虚拟页映射到不同颜色的物理页时可分散缓存压力。关键宏// 获取页面颜色低 N 位#defineMI_GET_PAGE_COLOR(x)((x)MmSecondaryColorMask)// 获取下一个系统颜色轮转#defineMI_GET_NEXT_COLOR()(InterlockedIncrement(MmSystemPageColor)MmSecondaryColorMask)// 获取下一个进程颜色#defineMI_GET_NEXT_PROCESS_COLOR(p)((p)-NextPageColorMmSecondaryColorMask)颜色数据结构typedefstruct_MMCOLOR_TABLES{PFN_NUMBER Flink;// 该颜色的第一个页PVOID Blink;// 该颜色的最后一个页ULONG Count;// 该颜色的页数量}MMCOLOR_TABLES;// 对每种列表Free/Zeroed和每种颜色都有一个链表头MMCOLOR_TABLES MmFreePagesByColor[2][MmSecondaryColors];颜色分配流程MiResolveDemandZeroFault() → Color MI_GET_NEXT_PROCESS_COLOR(Process) → MiRemoveZeroPage(Color) // 优先取对应颜色的零页 或 MiRemoveAnyPage(Color) // 优先取对应颜色的空闲页5. MiInitializePfn 初始化逻辑文件pfnlist.c:970功能当物理页被分配后初始化其 PFN 条目。VOID NTAPIMiInitializePfn(IN PFN_NUMBER PageFrameIndex,IN PMMPTE PointerPte,IN BOOLEAN Modified){Pfn1MI_PFN_ELEMENT(PageFrameIndex);Pfn1-PteAddressPointerPte;// 保存映射此页的 PTE 地址if(PointerPte-u.Hard.Valid1){// 来自 MmCreateProcessAddressSpace设为 Demand Zero PTEMI_MAKE_SOFTWARE_PTE(Pfn1-OriginalPte,MM_READWRITE);}else{Pfn1-OriginalPte*PointerPte;// 保存原始 PTE 内容}Pfn1-u3.e2.ReferenceCount1;// 初始引用计数 1Pfn1-u2.ShareCount1;// 初始共享计数 1Pfn1-u3.e1.PageLocationActiveAndValid;// 标记为活跃有效Pfn1-u3.e1.ModifiedModified;// 脏位// 获取页表 PFN递增其共享计数PointerPtePteMiAddressToPte(PointerPte);PageFrameIndexPFN_FROM_PTE(PointerPtePte);Pfn1-u4.PteFramePageFrameIndex;MI_PFN_ELEMENT(PageFrameIndex)-u2.ShareCount;}6. 引用计数管理6.1 MiDecrementShareCount文件pfnlist.c:1141功能递减 PFN 的共享计数ShareCount。当共享计数降至 0 时若为原型 PTE将原型 PTE 标记为 Transition将页面状态设为TransitionPage若引用计数为 1最后一引用检查MI_IS_PFN_DELETED已标记删除 → 直接插入空闲链表未标记删除 → 调用MiDecrementReferenceCountVOID NTAPIMiDecrementShareCount(IN PMMPFN Pfn1,IN PFN_NUMBER PageFrameIndex){ASSERT(Pfn1-u2.ShareCount0);if(!--Pfn1-u2.ShareCount){// ShareCount 降为 0if(Pfn1-u3.e1.PrototypePte){// 将原型 PTE 标记为 TransitionTempPte.u.Soft.Transition1;MI_WRITE_INVALID_PTE(PointerPte,TempPte);}Pfn1-u3.e1.PageLocationTransitionPage;if(Pfn1-u3.e2.ReferenceCount1){if(MI_IS_PFN_DELETED(Pfn1)){MiInsertPageInFreeList(PageFrameIndex);}else{MiDecrementReferenceCount(Pfn1,PageFrameIndex);}}else{InterlockedDecrement16(Pfn1-u3.e2.ReferenceCount);}}}6.2 MiDecrementReferenceCount文件pfnlist.c:1236功能递减 PFN 的引用计数ReferenceCount。当降至 0 时检查是否标记删除 → 是则插入空闲链表否则根据Modified位决定插入修改列表MmModifiedPageListHead或备用列表MmStandbyPageListHeadVOID NTAPIMiDecrementReferenceCount(IN PMMPFN Pfn1,IN PFN_NUMBER PageFrameIndex){InterlockedDecrement16(Pfn1-u3.e2.ReferenceCount);if(Pfn1-u3.e2.ReferenceCount)return;// 引用计数为 0if(MI_IS_PFN_DELETED(Pfn1)){MiInsertPageInFreeList(PageFrameIndex);}else{if(Pfn1-u3.e1.Modified1)MiInsertPageInList(MmModifiedPageListHead,PageFrameIndex);elseMiInsertStandbyListAtFront(PageFrameIndex);}}引用计数与共享计数的区别计数含义典型值ReferenceCountPFN 当前被引用的次数I/O、锁等释放时降为 0ShareCount映射到此物理页的 PTE 数量多个进程共享时 17. 全局统计变量freelist.c文件d:\reactos\ntoskrnl\mm\freelist.c// PFN 数据库基址——所有 PFN 条目的数组PMMPFN MmPfnDatabase;// 当前可用物理页数Free Zeroed StandbyPFN_NUMBER MmAvailablePages;// 系统启动时可用的物理页数PFN_NUMBER MmResidentAvailablePages;// 总已提交页面数commit chargeSIZE_T MmTotalCommittedPages;// 各分类的提交计数SIZE_T MmSharedCommit;// 共享内存提交SIZE_T MmDriverCommit;// 驱动提交SIZE_T MmProcessCommit;// 进程提交SIZE_T MmPagedPoolCommit;// 分页池提交// 峰值提交计数SIZE_T MmPeakCommitment;// 最大提交限制SIZE_T MmtotalCommitLimitMaximum;MiIncrementAvailablePages/MiDecrementAvailablePagespfnlist.c:69-118维护MmAvailablePages的增减同时检查低/高内存阈值当MmAvailablePages MmLowMemoryThreshold→ 触发低内存事件当MmAvailablePages MmHighMemoryThreshold→ 触发高内存事件当MmAvailablePages MmMinimumFreePages→ 调用MmRebalanceMemoryConsumers()回收内存8. LRU 用户页管理旧版 MM文件d:\reactos\ntoskrnl\mm\freelist.c旧版 MM 通过双向链表维护用户物理页的 LRULeast Recently Used顺序PMMPFN FirstUserLRUPfn;// LRU 链表头最早使用PMMPFN LastUserLRUPfn;// LRU 链表尾最近使用PFN 条目中的 LRU 指针Pfn-PreviousLRU// 前一个用户页Pfn-NextLRU// 下一个用户页关键函数MmGetLRUFirstUserPage()— 取 LRU 链表第一页并引用MmGetLRUNextUserPage(PreviousPage, MoveToLast)— 取下一页若MoveToLast为真则将当前页移到链表尾部避免频繁换出早期映射的 DLL 如 ntdllMmInsertLRULastUserPage()— 将页插入 LRU 链表尾部MmRemoveLRUUserPage()— 从 LRU 链表中移除用途内存平衡器balance.c通过 LRU 链表遍历用户页面选择换出候选页。附录Pfnlist.c 函数一览函数行号功能MiZeroPhysicalPage122通过超空间映射清零一个物理页MiUnlinkFreeOrZeroedPage137从空闲/零页链表中拆下一个 PFN按颜色MiUnlinkPageFromList265从备用/修改链表中拆下一个 PFNMiRemovePageByColor364按颜色从空闲/零页链表中移除一个 PFNMiRemoveAnyPage477取任意一页优先空闲MiRemoveZeroPage537取零页优先已清零MiInsertPageInFreeList611插入空闲链表MiInsertStandbyListAtFront718插入备用链表头部MiInsertPageInList779通用页面插入MiInitializePfn970初始化 PFN 条目MiDecrementShareCount1141递减共享计数MiDecrementReferenceCount1236递减引用计数MiInitializePfnForOtherProcess1301为其他进程初始化 PFN