《Windows核心编程》读书心得——内存(堆和栈)(5)

线程栈:

系统在线程创建的时候,会为线程栈顶预订一块地址空间,并调拨一些物理存储器,这块地址空间称为线程栈。

大小:线程栈的默认大小为1MB(该值可以通过编译器的/F选项,或连接器/STACK来设置),连接器会把栈的大小写入exe或dll的PE头文件中。

保护属性:默认都是PAGE_READWRITE。

栈顶:一开始,系统会给区域顶部两个页面调拨物理存储器,并把指针指向第一个页面,称为栈顶。第二个页面称为防护页面

栈底:系统永远不会给栈底页面调拨物理存储器(目的是为了保护栈内存操作不越界)。若代码访问了栈底后面的内存,将引起内存破坏,称为“栈下溢”。

 

堆:

堆是一块预订的地址空间,它始终是从页交换文件中分配的。

优点:堆非常适合分配大量的小型数据,是用来管理链表和树的最佳方式。

缺点:分配和释放速度比其他方式慢,且无法再对物理存储器的调拨和撤销调拨进行直接控制,灵活性差一点

进程的默认堆:进程初始化的时候,系统会在进程地址空间中创建一个默认堆,默认大小为1MB(该值可通过/HEAP连接器改变)。默认堆的访问必须一次进行,即任何时候只能有一个线程从默认堆中分配或释放内存。默认堆在进程创建之前由系统自动创建,在进程终止后自动销毁。GetProcessHeap()函数可获得默认堆的句柄。

基于效率考虑,同一个堆中最好不要分配大小不同的对象。

额外堆的使用方法:

(1)创建堆:HeapCreate(DWORD fdwOptions,SIZE_T dwInitialSize,SIZE_T dwMaximumSize)。fdwOptions:堆的属性(HEAP_NO_SERIALIZE:不使用独占的方式使用堆,该属性是不安全的,建议不用;HEAP_CREATE_ENABLE_EXECUTE:如果想在堆中存放可执行代码,需要选中该属性);dwInitialSize:初始大小;dwMaximumSize:能够增长到的最大大小。

(2)分配内存块:HeapAlloc(),即从HeapCreate()创建的堆中划分出来一块内存。

(3)调整内存大小:HeapReAlloc()。

(4)获得内存大小:HeapSize()。

(5)释放内存:HeapFree()

(6)销毁堆:HeapDestroy()。如果在进程终止前,我们没有调用HeapDestroy函数显式销毁堆,那么系统会在进程退出时自动帮我们销毁。

(7)其它函数:

GetProcessHeaps():得到进程中所有堆的句柄;

HeapValidate():验证堆的完整性(遍历所有内存块,确保没有一块内存被破坏);

HeapCompact():让堆中闲置的内存块能够重新接合在一起;

HeapLock()、HeapUnLock():加锁和解锁,用于线程同步(为了保证对堆的访问时依次的,HeapAlloc、HeapSize、HeapFree内部会调用这两个函数)。

HeapWalk():只用于调试,允许我们遍历堆的内容。

(8)C 函数内部调用:malloc函数内部会调用HeapAlloc();free函数内部会调用HeapFree()。而new内部会调用malloc(),delete内部会调用HeapFree()。

 即:

VirtualAlloc()、VirtualFree();

HeapAlloc()、HeapFree();

malloc()、Free();

new、delete;

是层层递进的关系。

 

 

你可能感兴趣的:(《Windows核心编程》读书心得——内存(堆和栈)(5))