现在的位置: 首页 > 综合 > 正文

Windows 95 System Programming SECRENTS学习笔记—第五章(4)

2012年08月04日 ⁄ 综合 ⁄ 共 4040字 ⁄ 字号 评论关闭

GetProcessHeap

    使用一个Win32 Heap函数,首先你得有一个heap handle。大部分程序都使用KERNEL32在程序产生时给与的一个默认堆(default heap)。你可以调用GetProcessHeap获得其Heap handle。这个函数很简单,它取出KERNEL32的一个全局变量,指向当前进程的process database。其中存放有进程的默认堆的句柄(handle)。

 

HeapAllocIHeapAlloc

    HeapAlloc,如其名称所示,你可以利用它从某个heap中分配一块内存。它其实只是做参数检验的工作,真实分配内存是由IHeapAllocHPAlloc完成。HeapAlloc检查hHeap所代表的Heap的大小是否足够容纳一个Heap表头。虽然它也可以检查其它成员如signaturechecksum,但很奇怪的是它忽略那些成员。如果hHeap通过测试,HeapAlloc就调用IHeapAlloc

 

    IHeapAlloc其实只是HPAlloc的外包函数。后者才是真正的HeapAlloc“主体”。在调用HPAlloc之前,IHeapAllocdwFlags(调用者传入的标志)做了一些处理。唯一可能幸存的是HEAP_ZERO_MEMORYHEAP_GENERATE_EXCEPTIONS两个标志。前者的值(如果幸存的话)比其原值左移三位。

 

HPAlloc

    这才是HeapAlloc的主体。它首先检查,要求的区块大小是否太大。太大意味0x0FFFFF98(接近256MB)。接下来HPAlloc调用hpTakeSem,这使得heap表头中的critical section被取得。从此,进程中就没有起他线程可以调用HPAlloc,直到HPAlloc结束为止。在调试版中,hpTakeSem也会随机检验heap是否被摧毁。hpTakeSem还可以遍历整个heap,检查checksum以及signature。你可以利用HeapSetFlags切换这些能力。HeapSetFlags加入Windows 95的时间太晚,以至于我没有办法把它放到本书中来讲。

 

    HPAlloc接下来去出区块大小参数,调整使它接近4的倍数(也要考虑arena的大小)。最小值是0x18。在减去arena的大小之后,留给使用者的只剩8个位。知道区块大小之后,HPAlloc就能决定搜寻四个自由链表中的那一个。找到正确的链表之后,HPAlloc遍历整个链表(使用自由区块的prev指针)以找出第一个够大的区块。

 

    这个时候,让我们假设HPAlloc找到了一个够大的区块。于是它调用hpCarve(稍候我将介绍)。hpCarve函数检查一个区块,看看它是否刚好够大,或是可以分裂为两块。如果需要分裂,hpCarve处理所有的工作,包括产生新的arena、初始化prevnext等等。分裂出来的其中一块刚好够大,满足HPAlloc的需求。另一块被放到自由链表之中。

 

    hpCarve返回之后,HPAlloc将新的区块的arena成员初始化。除了“取得HPAlloc调用者的EIP”,以及“计算前三个成员的checksum”之外,其余只是一些简单的设定动作。最后,HPAlloc释放heap的临界区对象,返回一个指针,指向arena之后的第一个字节。

 

如果HPAlloc没有发现一个自由区块的话,并且heap允许自动增长(产生堆时,dwMaximumSize被指定为0),HPAlloc则需要产生一个新的sunheap。先前我说过,一个subheap是另一个独立空间,内含一些heap区块。KERNEL32负责跟踪所有的subheaps,作法是把它们统统维护在一个链表之中。如果需要产生subheapKERNEL32会决定其初始大小(通常是4KB),并调用VMM报留一些pages。接下来HPAlloc调用HPInit将新的subheap的表头初始化。初始化之后,HPAlloc把它安插到subheaps所组成的链表中。最后,HPAlloc跳到“搜寻自由链表”的起始处。我想,这一次应该可以找到足够大小的区块了。

 

Windows 95中,Win32堆中的内存最初都处于reserved,并为committed。如果我们有1MB堆并且在还不需要这1MB内存时,并不会提交实际的内存页。当程序触及被reserved而尚未被committedpage时,会引发page fault。因此,堆函数必须确定所有使用中的区块涉及到的pages都作了commit动作。在Windows 95中,系统并不是用结构化异常来做commit动作。

 

HeapSizeIHeapSize

    HeapSize获得一个指针,指向先前分配的一块内存,并返回其大小(不含arena)。

 

HeapFreeIHeapFree

    HeapFree仅负责参数检验。真实的动作发生在IHeapFreex_HeapFree中,除了释放指定的堆内存,该函数还会检查是否有必要进行自由区块的合并。

 

HeapReAllocIHeapReAlloc

    HeapReAlloc对原已存在的一个Win32堆重新配置其大小。HeapReAlloc只负责参数检验,其动作和HeapFree所做的一样。

 

    Windows 95中,IHeapReAlloc有一点诡异,它会重新按排dwFlags参数,能通过的标志如下:

HEAP_GENERATGE_EXCEPTIONS

HEAP_NO_SERIALIZE

HEAP_ZERO_MEMORY

HEAP_REALLOC_IN_PLACE_ONLY

 

在进行重新分配时,HeapReAlloc有四种情况需要考虑:

l         新区块比原区块小

l         新区块和原区块大小相差不多

l         新区块比原区块大。而堆中的下一个区块是自由的,并且可以和原区块合并其来,形成满足要求的新区块。

l         新区块比原区块大。而堆中的下一个区块并不自由,或者虽然它是自由的,但和原区块合并后还是无法满足要求。

 

HeapCreate

    HeapCreate是所有Win32堆函数的根源。每个Win32程序在开始之前都有一个默认的堆。此外,程序还可以调用HeapCreate产生另外的堆。除了被应用程序使用之外,KERNEL32也调用HeapCreate在全局共享内存中产生堆,并用这些堆来对系统数据结构(诸如线程或进程相关资料)

 

    产生一个Win32堆的过程可分为两个部分。第一部分是保留内存并将其连接到进程的堆链表上,另一部分是初始化堆表头。

 

HeapDestroyIHeapDestroy

    与前面介绍的函数类似,HeapDestroy只是做参数检验工作,实际的摧毁Win32堆的动作是由IHeapDestroy完成的。摧毁Win32堆并不像释放堆还给操作系统那么简单。有两件事情使它比较复杂。第一,所有未以HEAP_NO_SERIALIZE属性产生出来的堆,都持有一个临界区对象。IHeapDestroy检查要摧毁的堆是否拥有此对象,并适当的释放之。

 

    另一个复杂原因是堆链表。如果IHeapDestroy只是单单释放堆所占用的页,这个堆链表就会被破坏掉。IHeapDestroy必须遍历整个链表,并更新之。

 

    在链表被更新之后,IHeapDestroy调用VMM_PageFree,释放堆所拥有的页。仅调用一次可能不足以释放所有的页。为什么?如果堆使用者做了许多的配置,或是一个非常大的配置,HeapAlloc可能产生出额外的subheaps并追加到subheap链表上。因此,IHeapDestroy必须保证释放main heap以及任何一个subheap

 

    最后请注意一点,程序退出之前,系统不会自动调用HeapDestroy。我推测如果进程的地址空间消失了,所有的堆内存也就被释放了吧。

 

HeapValidate

    这是一个Windows NT函数。它扫描一个Win32堆,检查其一致性。其实我看不出有什么理由它不应该出现在Windows 95 API中。

 

HeapCompact

    这也是个Windows NT函数。它会尝试合并自由区块并将Win32堆中未使用的页统统decommit掉。Windows 95已经在日常维护中完成了这些事情,所以它没有存在的必要。

 

GetProcessHeaps

   该函数仅存在于Windows NT系列操作系统中,该函数返回一个由堆句柄组成的数组。

 

 

HeapLock

   这也是一个Windows NT函数,获得Win32堆的临界区对象。

 

HeapUnLock

   也是Windows NT函数,释放Win32堆的临界区对象。

 

HeapWalk

    也是一个Windows NT函数,遍历一个Win32堆的所有区块。

笔记:

Windows XPWindows Server 2003系列中,增加了下面两个新的堆函数:

HeapSetInformation

HeapQueryInformation

 

 

Win32  Virtual函数

Win32堆函数

VirtualAlloc

HeapCreate

VirtualAllocEx

HeapSize

VirtualFree

HeapAlloc

VirtualFreeEx

HeapReAlloc

VirtualLock

HeapLock

VirtualUnlock

HeapUnLock

VirtualProtect

HeapFree

VirtualProtectEx

HeapDestroy

VirtualQuery

HeapValidate

VirtualQueryEx

HeapCompact

 

HeapSetInformation

 

HeapQueryInformation

 

抱歉!评论已关闭.