线程栈:
系统在线程创建的时候,会为线程栈顶预订一块地址空间,并调拨一些物理存储器,这块地址空间称为线程栈。
大小:线程栈的默认大小为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;
是层层递进的关系。