Windows核心编程学习笔记--第18章

来源:互联网 发布:three.js 教程 编辑:程序博客网 时间:2024/05/19 07:07

 

18章堆

先讲优缺点,产生兴趣,再讲堆是什么,怎么用。

18.1进程的默认堆

18.2为什么要创建额外的堆

18.3如何创建额外的堆

18.4其他堆函数

---------标记的为自己的分析。

先说说优缺点:堆非常适合分配大量的小型数据。与虚拟内存和内存映射文件相比,堆是用来管理链表和树的最佳方式。优点:不必理会分配粒度和页面边界这类事情。缺点:分配和释放内存块的速度比其他方式慢,且无法再对物理存储器的调拨和撤销调拨进行直接控制。

堆是什么:堆就是一块预订的地址空间区域。刚开始,区域内的大部分页面都没有调拨物理存储器。随着我们不断从堆中分配内存,堆管理器会给堆调拨越来越多的物理存储器。这些物理存储器始终是从页交换文件中分配的。释放堆中的内存块时,堆管理器会撤销已调拨的物理存储器。

-------说明有个堆管理器,调拨和释放物理存储器都由堆管理器来控制,而且只能从页交换文件中分配。程序员只用从堆中分配内存,由堆管理器来调拨和释放物理存储器。

 

18.1进程的默认堆

定义:进程初始化时,系统会在进程地址空间中创建一个堆。默认大小为1M

应用:许多windows函数会用到进程的默认堆。当程序有多个线程同时调用windows函数时,对默认堆的访问必须依次进行。即:系统保证一次只让一个线程从默认堆中分配或释放内存块。

一个进程同时可有多个堆,进程在整个生命周期内可创建和销毁这些堆。但,默认堆在进程开始之前由系统自动创建,进程终止后自动销毁,不受人为控制。每个堆都有一个用来标识自己的堆句柄,所有分配和释放内存块的堆函数都会在参数中用到这个堆句柄。GetProcessHeap可获得进程的默认堆的句柄。---------有啥用,又不能控制。

18.2为什么要创建额外的堆

         这些原因可能为:

对组件进行保护

更有效的内存管理

局部访问

避免线程同步的开销

快速释放

18.3如何创建额外的堆

HANDLE  HeapCreate(

         DWORD  fdwOptions,

         SIZE_T  dwInitialSize,//一开始要调拨给堆的字节数。

         SIZE_T  dwMaximumSize);//表示堆所能增长到的最大大小。若为0,则堆没有指定的上限。从堆中分配内存会使堆不断增大,直到用尽所有的物理存储器为止。

从堆中分配内存时,HeapAlloc函数执行以下操作:

1)遍历已分配内存的链表和闲置内存的链表。

2)找到一块足够大的闲置内存块。

3)分配一块新的内存,也就是将刚找到的闲置内存块标记为已分配。

4)将新分配的内存块添加到已分配内存的链表中。

fdwOptions取值:

HEAP_NO_SERIALIZE:尽量不用。不指定HEAP_NO_SERIALIZE标识时,只允许一个线程独占堆及其链表的访问,直到所必须的操作都已经完成(HeapAlloc的四步操作全部完成)。当且仅当进程中的线程独占访问堆(通过同步机制或者仅有一个线程访问堆)时,才可指定此属性。

HEAP_GENERATE_EXCEPTIONS:每当堆中分配或重新分配内存块失败时,抛出一个异常。

HEAP_CREATE_ENABLE_EXCUTE:可在堆中存放可执行代码。

18.3.1从堆中分配内存块

PVOID  HeapAlloc(

HANDLE  hHeap,

DWORD  fdwFlags,

SIZE_T  dwBytes);

fdwFlags取值:

HEAP_ZERO_MEMORY:在HeapAlloc返回前把内存块的内容都清零。

HEAP_GENERATE_EXCEPTIONS:同HeapCreateHeapCreate指定时,此处不必指定,整个堆有这个属性,从此堆分配的内存都具有此属性。HeapCreate未指定,此处指定时,仅分配到达内存有此属性,堆中其他内存无此属性。

HEAP_NO_SERIALIZE:同上,不要用。

在分配大块内存(1MB或更多)时应避免使用堆函数,用VirtualAlloc

         若分配大量不同大小的内存块,那么堆管理器内部用来处理分配请求的默认算法可能会产生地址空间碎片:由于所有可用内存块都不够大,因此系统无法找到一块足够大的闲置内存块。在xpserver2003之后的版本中,可强制操作系统在分配内存时使用一种叫低碎片堆的算法。在多处理器的机器上,低碎片堆的性能得到了极大的提高。下面代码用来切换到低碎片堆:

ULONG  HeapInformationValue = 2;

if (HeapSetInformation(hHeap, HeapCompataibilityInformation, &HeapInformationValue, sizeof(HeapInformationValue))

{//hHeap is turned into a low fragmentation heap}

else

{//hHeap can’t be turned into a low fragmentation heap.Maybe because it has been created with the HEAP_NO_SERIALIZE flag}参考P498

18.3.2调整内存块的大小

PVOID  HeapReAlloc(

HANDLE  hHeap,

DWORD  fdwFlags,

PVOID  pvMem,

SIZE_T  dwBytes);

18.3.3获得内存块的大小

         分配一块内存后,可调用HeapSize来得到这块内存的实际大小:

SIZE_T  HeapSize(

HANDLE  hHeap,   //堆标识

DWORD  fdwFlags,        //0HEAP_NO_SERIALIZE

LPCVOID  pvMem);        //内存块的地址

18.3.4释放内存块

BOOL  HeapFree(

HANDLE  hHeap,

DWORD  fdwFlags,        //0HEAP_NO_SERIALIZE

PVOID  pvMem);释放内存可能会使堆管理器撤销一些已经调拨的物理存储器。

18.3.5销毁堆

BOOL  HeapDestroy(HANDLE  hHeap);

18.3.6C++中使用堆:示例了如何在一个堆中分配所有实例。

18.4其他堆函数:P503

原创粉丝点击