内存管理
物理地址的管理
物理内存
- 最大物理内存(x86)
- 10-10-12分页 最多识别物理内存为4GB
- 2-9-9-12分页 最多识别物理内存为64GB
- 操作系统限制
- 为什么在Xp中,已经是2-9-9-12分页了,但是还是只能识别4GB的内存空间呢?
- 实际的物理内存
- MmNumberOfPhysicalPages * 4 = 物理内存(在Xp上的高版本已不再导出)
可以使用winDbg查看
!vm
可以看到Physical Memory
为3145176大约3G的内存,这和我们在任务管理器中看到的一致
物理内存如何管理
- 全局数组
- 数组指针:_MMPFN* MmPfnDatabase(起始位置)
- 数组长度:MmNumberOfPhysicalPages
- 数组成员
- _MMPFN(一个物理页对应一个这样的结构体)
在winDbg中查看
dd MmPfnDatabase
dt _MMPFN
我们可以看下这个结构体有多大,最后一个结构体成员u4占4个字节,所以这个_MMPFN一共占1C个字节
如何通过物理地址查找对应的物理页结构体描述呢?
从上图中可以知道83e00000
是第一个物理页结构体,它所对应的物理页就是0000,那么一个物理页结构体占1C个字节,那么第二个物理页结构体就是83e00000 + 1C * 1
,后面以此内推,相反如果我们知道了一个物理地址那么如何知道它对应的物理页结构呢?比如8000这个地址,首先减3个0,就是8,然后用MmPfnDatabase
首地址83e00000 + IC * 8
就得到了对应地址的结构体
物理页的不同状态
物理页在不同情况下所处的状态是不一样的,比如当前物理页不够用了,当前物理页损坏了,当前物理页正在被使用等。在上面结构体当中u3这个成员就描述了当前物理页所处的状态
// Mm internal
typedef struct _MMPFN
{
union
{
PFN_NUMBER Flink;
ULONG WsIndex;
PKEVENT Event;
NTSTATUS ReadStatus;
SINGLE_LIST_ENTRY NextStackPfn;
// HACK for ROSPFN
SWAPENTRY SwapEntry;
} u1;
PMMPTE PteAddress;
union
{
PFN_NUMBER Blink;
ULONG_PTR ShareCount;
} u2;
union
{
struct
{
USHORT ReferenceCount;
MMPFNENTRY e1;
};
struct
{
USHORT ReferenceCount;
USHORT ShortFlags;
} e2;
} u3;
union
{
MMPTE OriginalPte;
LONG AweReferenceCount;
// HACK for ROSPFN
PMM_RMAP_ENTRY RmapListHead;
};
union
{
ULONG_PTR EntireFrame;
struct
{
ULONG_PTR PteFrame:25;
ULONG_PTR InPageError:1;
ULONG_PTR VerifierAllocation:1;
ULONG_PTR AweAllocation:1;
ULONG_PTR Priority:3;
ULONG_PTR MustBeCached:1;
};
} u4;
// e1对应的结构体
typedef struct _MMPFNENTRY
{
USHORT Modified:1;
USHORT ReadInProgress:1; // StartOfAllocation
USHORT WriteInProgress:1; // EndOfAllocation
USHORT PrototypePte:1;
USHORT PageColor:4;
USHORT PageLocation:3; // 当前页所处的状态
USHORT RemovalRequested:1;
USHORT CacheAttribute:2;
USHORT Rom:1;
USHORT ParityError:1;
} MMPFNENTRY;
物理页空闲下的6种状态(windows通过这6个链表把所有的不同状态的物理页给串起来了):
Windows 内存管理链表详解
1. MmZeroedPageListHead
(清零页链表)
- 状态: 已显式清零(内容全为0)
- 用途:
- 分配给需要干净内存的进程(如进程创建时)
- 避免敏感数据泄漏
- 特点:
- 由零页线程异步清零
- 分配时无性能开销
2. MmFreePageListHead
(空闲页链表)
- 状态: 空闲但可能含残留数据
- 用途:
- 快速分配内核非分页内存
- 不要求清零的场景
- 特点:
- 分配速度最快
- 可能包含历史数据
3. MmStandbyPageListHead
(备用页链表)
- 状态: 含有效缓存数据
- 用途:
- 工作集修剪后的缓存页
- 支持软缺页快速恢复
- 特点:
- 可快速重用
- 仍关联原进程VAD
4. MmModifiedPageListHead
(已修改页链表)
- 状态: 脏页(未写入磁盘)
- 用途:
- 暂存待写入磁盘的修改页
- 特点:
- 需要写回操作
- 崩溃可能导致数据丢失
5. MmModifiedNoWritePageListHead
(不可写修改页链表)
- 状态: 脏页(禁止写回)
- 用途:
- 设备内存映射
- AWE内存分配
- 特点:
- 直接丢弃内容
- 需驱动程序显式请求
6. MmBadPageListHead
(坏页链表)
- 状态: 硬件损坏页
- 用途:
- 隔离故障内存
- 特点:
- 永不分配
- 记录WHEA事件