Windows内存管理分析(二)

Windows内存管理分析(二)

二、物理内存的管理

内核管理的最小单位是页面,首先来看物理页面的表示 MMPFN描述了一个物理页面所需要的信息

Windows内存管理分析(二)

Windows内存管理分析(二)

NextStackPfn指向一个栈的物理页面,这个字段用于要删除或者增加内核栈的空间的时候用于指向下一个物理页面、PteAddress指向MMPTE结构,代表一个页表项

MMPFN的u3.e1是一个MMPFN_ENTRY结构

Windows内存管理分析(二)

描述这个页面内核一些数据结构需要的字段,例如PageColor是代表这个页面的颜色,至于其他一些成员等见到再进行讨论。PfnUsage代表这个物理页面的用途,类型是一个枚举值

MmPfnDatabase是由MMPFN组成的数组,称为PFN数据库,通过物理页面的编号来确定数组的下标,比如0号页面对应数组的0号元素,Flink和Blink可以被插入到一个链表中,那为什么已经有数据库将每一个物理页的信息都存储了,还要用链表串在一起呢?这是因为系统维护了几个链表做特定功能使用,这些链表用到的成员就是Flink和Blink。

MMPTE_HARDWARE跟体系相关,x86定义如下,可看出跟IA-32的PTE/PDE是一致的

Windows内存管理分析(二)

Windows内存管理分析(二)

MMPTE用来表示页表项PTE,但是它也可以用作PDE或者PPE,PXE,如果MMPTE包含一个有效的地址,那么就使用hard字段执行MMPTE_HARDWARE,MMU可以用它来完成地址的转换。上面说到,系统维护了几个链表来做特定用途,链表的定义是

Windows内存管理分析(二)

成员Flink和Blink就是上文提到PFN的两个成员,MMLISTS是枚举值,代表这个链表的类型

系统维护的分别是

Windows内存管理分析(二)

就绪(Standby)、已修改(Modified)、无写修改(ModifiedNoWrite),空闲(Free),只读(Rom),损坏(Bad),零化(Zeroed)

并且加入了MmPageLocationList数组之中,可以在数组中利用链表枚举类型MMLISTS来进行方便的定位。如下所示

Windows内存管理分析(二)

上文提到的MMPFN_ENTRY结构体的成员PageLocation就代表物理页具体存储在这个数组的哪个元素

Windows内存管理分析(二)

MMCOLOR_TABLES记录了一个链表,可以用来组织已经着色的页面

有了上述结构体的大概认识,我们来结合具体函数分析这些结构体的使用。分配物理内存使用MmAllocPage函数

Windows内存管理分析(二)

参数为要申请的内存类型,然后返回一个物理页面编号。获取PFN的自旋锁后,从零化页面找出一个物理页号(并在原零化链表中移除),然后根据这个页号在PFN数据库中获取具体的PFN结构体信息,进行初始化各项成员,引用计数设置为1。这样就完成了一个物理页面的申请。我们来分析MiRemoveZeroPage的实现,分析如何申请一个0化的页面。分段阅读

Windows内存管理分析(二)

MmFreePagesByColor是一个PMMCOLOR_TABLES数组,也就是一个二维数组,定义如下

Windows内存管理分析(二)

MmSecondaryColors和下面出现的MmSecondaryColorMask是辅助颜色值和辅助掩码,MmSecondaryColors我个人理解为当前可用最大的颜色值。

FreePageList是一个上文提到的MMLIST枚举值,转换为整数是1,所以数组有2个元素,访问时通过枚举值进行访问。这个数组第一个元素是零化的着色页面,第二个元素是空闲着色的页面。数组的二维是一个由COLOR颜色值作下标的数组,通过COLOR值就可以获取到对应颜色的页面链表,该链表的所有颜色就是这个COLOR。我们可以看到从0化页面的对应颜色值取出了一个链表。

Windows内存管理分析(二)

接下来判断链表的头个元素的值是否是LIST_HEAD,LIST_HEAD是宏定义为-1,也就是这个链表中如果没有值的话就要用-1表示。如果对应颜色的物理页面链表为空,没有元素的话,就应该从系统维护的零化页面链表中取出一个新页面,这里通过PageIndex&MmSecondaryColorMask计算出新的COLOR值,可以看出COLOR值实际上是通过物理页面下标来进行确定的。如果系统维护的零化页面链表也为空,更新一下Zero值,表明等一下取出来的页面应该手动去零化,然后从系统空闲页面链表MmFreePageListHead取出页面,同样更新COLOR值,这时候如果MmFreePageListHead也为空,我们可以看到暂未实现。

Windows内存管理分析(二)

根据页面下标来取出PFN数据库对应的PFN项目,进行检查,如果需要零化就进行零化处理。我们分析MiRemovePageByColor的实现,分段阅读

Windows内存管理分析(二)

首先从页面下标获取对应MMPFN项,然后通过该项的MMPFN_ENTRY获取得到页面当前所处的系统维护的链表,这是通过PageLocation来获得的,获取到链表头后,进行Total的减1,代表链表中元素个数减一

Windows内存管理分析(二)

然后就是数据结构相关内容,从系统维护的链表中删除该结点。

Windows内存管理分析(二)

接下来取出MmFreePagesByColor对应的元素,也相应的将其删除。更新计数。

我们还看到使用了MiDecrementAvailablePages函数,这个函数主要是递减全局变量MmAvailablePages,如果过低就判断为系统可用内存过低触发事件来修剪。

通过SouceInsight查看MmAllocPage的函数为MmRequestPageMemoryConsumer,它实现了一个更通用的,可以为特定请求进行申请内存。

Windows内存管理分析(二)

Consumer为宏定义

Cache代表缓存用,USER是用户用,SYSTEM是系统使用,MAXIUM当前共有几种用途,就是这3种用途

再看一个结构体

Windows内存管理分析(二)

表明一个特定用途的消费者。系统将消费者分类存入了一个数组

Windows内存管理分析(二)

表明一共3种消费者

Windows内存管理分析(二)

首先增加该消费者类型对应数组的页面使用数量,如果页面数量使用次数过多,并且当前线程不是平衡用的线程,就要修剪腾出一些物理页面

Windows内存管理分析(二)

用MmAllocPage申请一个页面返回 如果是用户进行申请页面MmInsertLRULastUserPage 设置用户PFN位图MiUserPfnBitMap,但是实际上在此处是用户申请这个应该永远不成立。前面已经过滤了只剩下系统的消费者了。

Windows内存管理分析(二)

Windows内存管理分析(二)

如果系统可用页数已经小于最小可用页数,那么判断调用者是否可用等待,如果不能等待,直接返回没有内存错误,如果可以等待,就等待平衡线程去修剪内存腾出物理页面,如果这时候还没有页码,那么就是严重错误了。这里我们可以看到系统消费者和其他消费者的一个区别,如果系统消费者需要内存,就申请一个物理页面,然后调用平衡线程去强制修剪其他的,但是如果是非系统消费者,如果不想等待就直接返回没有内存,如果要等待就必须要等其他物理内存腾出,才能轮得到它申请到。

Windows内存管理分析(二)

接下来是最后的申请页面操作,前面有判断的条件都不成立时,最终就执行到这里。

接下来分析页面释放函数

Windows内存管理分析(二)

Windows内存管理分析(二)

函数很短,首先是判断引用计数是否为1,如果是1代表是这个页面目前只被引用一次,可以被挂入空闲链表

在这个函数中递减了页面引用计数,然后如果为0就会被挂入空闲链表之中。

让我们再看一下这个函数

Windows内存管理分析(二)

这个函数一般是这个页面又被引用的时候进行使用,至此我们可以看到一个物理页面的生命周期,首先是被申请,引用计数为1,接下来可能会被继续引用(例如2个不同的虚拟地址页面实际上指向一个物理页面),当引用计数为0的时候,就会被挂入空闲链表MmFreePageListHead之中,并且也同样挂入物理页面对应的颜色链表MmFreePagesByColor中

更多干货等着你~

http://weixin.qq.com/r/M3W7oxbE-0uArVLA9yAh (二维码自动识别)


分享到:


相關文章: