1. HeapAlloc:

 
MSDN上的解释为:HeapALloc是从堆上分配一块内存,且分配的内存是不可移动的(即如果没有连续的空间能满足分配的大小,程序不能将其他零散的空间利用起来,从而导致分配失败),该分配方法是从一指定地址开始分配,而不像GloabalAlloc是从全局堆上分配,这个有可能是全局,也有可能是局部。函数原型为:
LPVOID
HeapAlloc(
    HANDLE hHeap,
    DWORD dwFlags,
   SIZE_T dwBytes
    );
hHeap是进程堆内存开始位置。
dwFlags是分配堆内存的标志。包括HEAP_ZERO_MEMORY,即使分配的空间清零。
dwBytes是分配堆内存的大小。
其对应的释放空间函数为HeapFree。
2. GlobalAlloc:该函数用于从全局堆中分配出内存供程序使用,函数原型为:
HGLOBAL GlobalAlloc(
UINT uFlags,
SIZE_T dwBytes
);
uFlags参数含义
GHND   GMEM_MOVEABLE和GMEM_ZEROINIT的组合
GMEM_FIXED   分配固定内存,返回值是一个指针
GMEM_MOVEABLE   分配活动内存,在Win32中,内存块不能在物理内存中移动,但能在默认的堆中移动。返回值是内存对象的句柄,用函数GlobalLock可将句柄转化为指针
GMEM_ZEROINIT   将内存内容初始化为零
GPTR   GMEM_FIXED和GMEM_ZEROINIT的组合
一般情况下我们在编程的时候,给应用程序分配的内存都是可以移动的或者是可以丢弃的,这样能使有限的内存资源充分利用,所以,在某一个时候我们分配的那块内存的地址是不确定的,因为他是可以移动的,所以得先锁定那块内存块,这儿应用程序需要调用API函数GlobalLock函数来锁定句柄。如下: lpMem=GlobalLock(hMem); 这样应用程序才能存取这块内存。所以我们在使用GlobalAllock时,通常搭配使用GlobalLock,当然在不使用内存时,一定记得使用 GlobalUnlock,否则被锁定的内存块一直不能被其他变量使用。
GlobalAlloc对应的释放空间的函数为GlobalFree。
3. LocalAlloc:该函数用于从局部堆中分配内存供程序使用,函数原型为:
HLOCAL LocalAlloc(
UINT uFlags,
SIZE_T uBytes
);
参数同GlobalAlloc。
在 16位Windows中
LocalAlloc和GlobalAlloc是有区别的,因为在16位windows用一个全局堆和局部堆来管理内存,每一个应用程序或dll装入内存时,代码段被装入全局堆,而系统又为每个实例从全局堆中分配了一个64kb的数据段作为该实例的局部堆,用来存放应用程序的堆栈和所有全局或静态变量。而 LocalAlloc/GlobalAlloc就是分别用于在局部堆或全局堆中分配内存。
     由于每个进程的局部堆很小,所以在局部堆中分配内存会受到空间的限制。但这个堆是每个进程私有的,相对而言分配数据较安全,数据访问出错不至于影响到整个系统。
     而在全局堆中分配的内存是为各个进程共享的,每个进程只要拥有这个内存块的句柄都可以访问这块内存,但是每个全局内存空间需要额外的内存开销,造成分配浪费。而且一旦发生严重错误,可能会影响到整个系统的稳定。

    不过在Win32中,每个进程都只拥有一个省缺的私有堆,它只能被当前进程访问。应用程序也不可能直接访问系统内存。所以在Win32中全局堆和局部堆都指向进程的省缺堆。用LocalAlloc/GlobalAlloc分配内存没有任何区别。甚至LocalAlloc分配的内存可以被 GlobalFree释放掉。所以在Win32下编程,无需注意Local和Global的区别,一般的内存分配都等效于 HeapAlloc(GetProcessHeap(),...)。
LocalAlloc对应的释放函数为LockFree。
4. VirtualAlloc:该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页,如果用于内存分配的话,并且分配类型未指定MEM_RESET,则系统将自动设置为0;其函数原型:
LPVOID VirtualAlloc(
LPVOID lpAddress, // region to reserve or commit
SIZE_T dwSize, // size of region
DWORD flAllocationType, // type of allocation
DWORD flProtect // type of access protection
);
VirtualAlloc 可以通过并行多次调用提交一个区域的部分或全部来保留一个大的内存区域。多重调用提交同一块区域不会引起失败。这使得一个应用程序保留内存后可以随意提交将被写的页。当这种方式不在有效的时候,它会释放应用程序通过检测被保留页的状态看它是否在提交调用之前已经被提交。
VirtualAlloc对应的释放函数为VirtualFree。
5.Malloc:malloc 与free是C++/C语言的标准库函数,可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用 malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
6.New:new/delete 是C++的运算符。可用于申请动态内存和释放内存。C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。C++程序经常要调用C函数,而C程序只能用malloc /free管理动态内存。new 是个操作符,和什么"+","-","="...有一样的地位.
        malloc是个分配内存的函数,供你调用的.
        new是保留字,不需要头文件支持.
        malloc需要头文件库函数支持.new 建立的是一个对象,
        malloc分配的是一块内存.
        new建立的对象你可以把它当成一个普通的对象,用成员函数访问,不要直接访问它的地址空间
        malloc分配的是一块内存区域,就用指针访问好了,而且还可以在里面移动指针.
内存泄漏对于malloc或者new都可以检查出来的,区别在于new可以指明是那个文件的那一行,而malloc没有这些信息。new可以认为是malloc加构造函数的执行。new出来的指针是直接带类型信息的。而malloc返回的都是void指针。
 

B.heap and stack
  1、函数里的局部变量是在stack里的.  
  2、全局变量,用new、malloc等分配的内存是在heap里的.  
  3、什么时候用heap,什么时候用stack要看你所使用的内存生存期.  
  4、如果使用的变量只在函数里有用,建议用stack.因为heap很慢  
  5、如果使用很大块的内存,建议用heap.因为stack可能会溢出.  
  6、如果在函数里面分配的内存,还想在函数返回之后使用,要用new、malloc,或者定义成静态变量,静态变量是在heap里的.  

 

C. default heap
每一个Process都有自己的default heap,默认初始值为1M. GetProcessHeap()可以得到default heap的HANDLE. 然后可以使用HeapAlloc(...)在default heap中开辟内存。如果HeapAlloc开辟的内存小于1M,则直接使用process启动时自动开辟的1M default heap中的内存,如果大于1M,那么在heap中开辟新的内存,扩大default heap。
为兼容win16时代代码,GlobalAlloc, LocalAlloc具有一样的表现。
Every process in Windows NT has one heap called the default heap. Processes can also have as many other dynamic heaps as they wish, simply by creating and destroying them on the fly. The Win32 subsystem uses the default heap for all global and local memory management functions, and the C run-time library uses the default heap for supporting malloc functions. The heap memory functions, which indicate a specific heap by its handle, use dynamic heaps.
这个msdn中的说法有点问题,malloc应该不使用default heap,使用自己独有的heap。

 

D.Testing code

int _tmain(int argc, _TCHAR* argv[])
{
 char szstr10[1024*500];//1640 848
 char *szstr11 = new char[1024*1024];//2676 1876
 char *szstr12 = new char[1024*1024];//3712 2912
 delete[] szstr11;//0x00420040 2684 1884
 delete[] szstr12;//0x00530040 1652 852
 HANDLE hDefaultHeap = GetProcessHeap();
 char *szstr0 = (char *)HeapAlloc(hDefaultHeap, HEAP_GENERATE_EXCEPTIONS, sizeof(char)*1024*512); //0x00420020 1660 1368
 HeapFree(hDefaultHeap, HEAP_GENERATE_EXCEPTIONS, szstr0);//1656 852
 char *szstr1 = (char *)HeapAlloc(hDefaultHeap, HEAP_GENERATE_EXCEPTIONS, sizeof(char)*1024*1024*1024); //0x10330020 1660 1,051,480
 HeapFree(hDefaultHeap, HEAP_GENERATE_EXCEPTIONS, szstr1);//1656 852
 char *szstr2 = (char *)GlobalAlloc(GMEM_FIXED, sizeof(char)*1024*512);//0x00420020 1660 1368
 GlobalFree((HGLOBAL)szstr2); //1656 852
 char *szstr3 = (char *)GlobalAlloc(GMEM_FIXED, sizeof(char)*1024*1024*1024);//0x10330020 1660 1,051,480
 GlobalFree((HGLOBAL)szstr3); //1656 852
 char *szstr4 = (char *)malloc(sizeof(char)*1024*512);//0x00420040 2172 1368
 free(szstr4);//1656 852
 char *szstr5 = (char *)malloc(sizeof(char)*1024*1024*1024);//0x10330040, slow, 1,053,308 1,051,480
 free(szstr5);//slow 2680 852
 HANDLE hDHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS, sizeof(char)*1024*512, 0);//3192 1364
 char* szstr6 = (char *)HeapAlloc(hDHeap, HEAP_GENERATE_EXCEPTIONS, sizeof(char)*1024*512); //0x004a0020 3200 1884
 HeapFree(hDHeap, HEAP_GENERATE_EXCEPTIONS, szstr6);//3192 1364
 HeapDestroy(hDHeap);//2684 856
 int i;
 i = 1;
 
 return 0;
}

 

E.代码运行解析

GlobalAlloc和HeapAlloc的表现差不多,但是他们与new和malloc的表现不一样。new和malloc的表现差不多。
为兼容C Run time lib, malloc具有一样的表现。稍有不同的是,malloc在扩大了VM的同时,也扩大了Mem Usage. new 和malloc具有同样的表现。最奇怪的是当malloc分配大内存的时候,free之后居然Mem Usage多了大约1M出来。难道在这里就泄露了?在malloc 1G之前用new 1G,那么就会有1M在那里消失了,估计是系统用于管理去了。由此看来malloc和new的表现最接近,他们和GlobalAlloc有一定的区别.传说new关键字就是用malloc实现的
以下为另一个说法
C/C++ Run-time (CRT) allocator: Provides malloc() and free() as well as new and delete operators. Languages like Microsoft Visual Basic® and Java also offer new operators and use garbage collection instead of heaps. CRT creates its own private heap, which resides on top of the Win32 heap.
看起来这个说法跟表现差不多。new/malloc需要一个自己的动态heap,并且这个动态heap需要管理成本,这就是使用了new/malloc之后都会有一些内存一直被hold住。因为那个heap被系统管理,我们无法destroy它。
也许是由于年代问题,两篇msdn对crt实用heap的说法不一致。从表现来看,我倾向于后面的那篇。也许是MS修改了实现。