HeapAlloc和GlobalAlloc及malloc及new的性能区别和各自的优势

时间:2020-12-05 03:19:45
查了一下MSDN,只找到以下几点:
1、GlobalAlloc分配及内存操作速度最慢,相对于其它内存函数
2、HeapCreate创建的堆对象可以支持标准堆和低碎片堆,建议频繁分配不同大小的内存块时使用
3、堆都是不可移动的,因此像剪贴板就无法使用堆内存了,所以剪贴板函数要用GlobalAlloc函数来分配
4、堆分配的内存的一个最大的优点是可以集中统一释放,这是JAVA和C#可以实现内存回收的重要原因吧
5、malloc分配不成功,返回NULL,new分配不成功会挂掉,除非设置异常处理函数
6、new分配类对象时,会自动执行一遍构造函数,其它分配函数只纯分配内存,但只有堆分配支持代码执行
7、为什么说堆分配是管理大量小数据的最佳方式?
8、malloc分配和new分配也使用的也是在本进程堆中进行分配的吧?
教高手赐教
大粉送上,老赵笑纳, HeapAlloc和GlobalAlloc及malloc及new的性能区别和各自的优势

7 个解决方案

#1


该回复于2016-04-15 08:05:09被管理员删除

#2


计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构……

对学习编程者的忠告:
HeapAlloc和GlobalAlloc及malloc及new的性能区别和各自的优势多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程!
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步Debug版对应汇编一行!
单步Debug版对应汇编千行不如单步Release版对应汇编一行!

单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。

VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。

想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
但我又不得不承认:
 有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物;
 而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。
而我本人属前者。

不要企图依赖输出指针相关表达式...的值【比如printf("%p\n",...);或者cout<<...】来理解指针的本质,
而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=(void *)(...);】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。


这辈子不看内存地址和内存值;只画链表、指针示意图,画堆栈示意图,画各种示意图,甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗?本人深表怀疑!
这辈子不种麦不收麦不将麦粒拿去磨面;只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头,压面条,烤面包,……能从本质上理解面粉、理解面食吗?本人深表怀疑!!

提醒:
“学习用汇编语言写程序”

“VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习C和汇编的对应关系。”
不是一回事!

不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!

有人说一套做一套,你相信他说的还是相信他做的?
其实严格来说这个世界上古往今来所有人都是说一套做一套,不是吗?

无profiler不要谈效率!!尤其在这个云计算、虚拟机、模拟器、CUDA、多核 、多级cache、指令流水线、多种存储介质、……满天飞的时代!

#3


File: C:\windows_2000_source_code\win2k\private\sdktools\imagehlp\crt.c

     36: void * __cdecl
     37: malloc(
     38:     size_t sz
     39:     )
     40: {
     41: 
     42:     return RtlAllocateHeap( RtlProcessHeap(), 0, sz );
     43: 
     44: }


File: C:\windows_2000_source_code\win2k\private\ntos\rtl\heap.c

     86: RtlDebugCreateHeap (
     96: RtlDebugDestroyHeap (
    101: RtlDebugAllocateHeap (
    108: RtlDebugFreeHeap (
    115: RtlDebugSizeHeap (
    122: RtlDebugZeroHeap (
    135: RtlpCreateUnCommittedRange (
    140: RtlpDestroyUnCommittedRange (
    146: RtlpInsertUnCommittedPages (
    153: RtlpDestroyHeapSegment (
    158: RtlpExtendHeap (
    191: RtlCreateHeap (
   1133: RtlDestroyHeap (
   1316: RtlAllocateHeap (
   2075: RtlAllocateHeapSlowly (
   2931: RtlFreeHeap (
   3273: RtlFreeHeapSlowly (
   3655: RtlSizeHeap (
   3762: RtlZeroHeap (
   3962: RtlpCreateUnCommittedRange (
   4169: RtlpDestroyUnCommittedRange (
   4227: RtlpInsertUnCommittedPages (
   4422: RtlpFindAndCommitPages (
   4732: RtlpInitializeHeapSegment (
   4959: RtlpDestroyHeapSegment (
   5024: RtlpExtendHeap (
   5312: RtlpCoalesceFreeBlocks (
   5527: RtlpDeCommitFreeBlock (
   5849: RtlpInsertFreeBlock (
   6008: RtlpGetExtraStuffPointer (
   6070: RtlpGetSizeOfBigBlock (
   6117: RtlpCheckBusyBlockTail (

#4


File: C:\windows_2000_source_code\win2k\private\windows\base\client\gmem.c

     42: HGLOBAL
     43: WINAPI
     44: GlobalAlloc(
     45:     UINT uFlags,
     46:     SIZE_T dwBytes
     47:     )
     48: {
     49:     PBASE_HANDLE_TABLE_ENTRY HandleEntry;
     50:     HANDLE hMem;
     51:     LPSTR p;
     52:     ULONG Flags;
     53: 
     54:     if (uFlags & ~GMEM_VALID_FLAGS) {
     55:         SetLastError( ERROR_INVALID_PARAMETER );
     56:         return( NULL );
     57:         }
     58: 
     59:     Flags = 0;
     60:     if (uFlags & GMEM_ZEROINIT) {
     61:         Flags |= HEAP_ZERO_MEMORY;
     62:         }
     63: 
     64:     if (!(uFlags & GMEM_MOVEABLE)) {
     65:         if (uFlags & GMEM_DDESHARE) {
     66:             Flags |= BASE_HEAP_FLAG_DDESHARE;
     67:             }
     68: 
     69:         p = RtlAllocateHeap( BaseHeap,
     70:                              MAKE_TAG( GMEM_TAG ) | Flags,
     71:                              dwBytes ? dwBytes : 1
     72:                            );
     73: 
     74:         if (p == NULL) {
     75:             SetLastError( ERROR_NOT_ENOUGH_MEMORY );
     76:             }
     77: 
     78:         return p;
     79:         }
     80: 
     81:     p = NULL;
     82:     RtlLockHeap( BaseHeap );
     83:     Flags |= HEAP_NO_SERIALIZE | HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVEABLE;
     84:     try {
     85:         HandleEntry = (PBASE_HANDLE_TABLE_ENTRY)RtlAllocateHandle( &BaseHeapHandleTable, NULL );
     86:         if (HandleEntry == NULL) {
     87:             SetLastError( ERROR_NOT_ENOUGH_MEMORY );
     88:             goto Fail;
     89:             }
     90: 
     91:         hMem = (HANDLE)&HandleEntry->Object;
     92:         if (dwBytes != 0) {
     93:             p = (LPSTR)RtlAllocateHeap( BaseHeap, MAKE_TAG( GMEM_TAG ) | Flags, dwBytes );
     94:             if (p == NULL) {
     95:                 HandleEntry->Flags = RTL_HANDLE_ALLOCATED;
     96:                 RtlFreeHandle( &BaseHeapHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry );
     97:                 HandleEntry = NULL;
     98:                 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
     99:                 }
    100:             else {
    101:                 RtlSetUserValueHeap( BaseHeap, HEAP_NO_SERIALIZE, p, hMem );
    102:                 }
    103:             }
    104: Fail:   ;
    105:         }
    106:     except (EXCEPTION_EXECUTE_HANDLER) {
    107:         BaseSetLastNTError( GetExceptionCode() );
    108:         }
    109: 
    110:     RtlUnlockHeap( BaseHeap );
    111: 
    112:     if (HandleEntry != NULL) {
    113:         HandleEntry->Object = p;
    114:         if (p != NULL) {
    115:             HandleEntry->Flags = RTL_HANDLE_ALLOCATED;
    116:             }
    117:         else {
    118:             HandleEntry->Flags = RTL_HANDLE_ALLOCATED | BASE_HANDLE_DISCARDED;
    119:             }
    120: 
    121:         if (uFlags & GMEM_DISCARDABLE) {
    122:             HandleEntry->Flags |= BASE_HANDLE_DISCARDABLE;
    123:             }
    124: 
    125:         if (uFlags & GMEM_MOVEABLE) {
    126:             HandleEntry->Flags |= BASE_HANDLE_MOVEABLE;
    127:             }
    128: 
    129:         if (uFlags & GMEM_DDESHARE) {
    130:             HandleEntry->Flags |= BASE_HANDLE_SHARED;
    131:             }
    132: 
    133:         p = (LPSTR)hMem;
    134:         }
    135: 
    136:     return( (HANDLE)p );
    137: }

#5


引用 4 楼 zhao4zhong1 的回复:

老赵幸苦了,劳烦再把HeapAlloc和malloc的代码贴一下,然后大粉给你 HeapAlloc和GlobalAlloc及malloc及new的性能区别和各自的优势

#6


malloc的前面已经贴了。
File: C:\windows_2000_source_code\win2k\private\shell\win16\commctrl\mem.c
    192: void NEAR* NEAR HeapAlloc(HHEAP hhp, WORD cb)
    193: {
    194:     void NEAR* pb;
    195:
    196:     _asm {
    197:         push    ds
    198:         mov     ds,hhp
    199:     }
    200:
    201:     pb = (void NEAR*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cb);
    202:
    203:     if (pb)
    204:         ((HEAP NEAR*)0)->cAlloc++;
    205:
    206:     _asm {
    207:         pop     ds
    208:     }
    209:
    210:     return pb;
    211: }

http://bbs.csdn.net/topics/390374955里面有windows_2000_source_code的下载链接

#7


看来malloc还真的不是线程安全的。

#1


该回复于2016-04-15 08:05:09被管理员删除

#2


计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构……

对学习编程者的忠告:
HeapAlloc和GlobalAlloc及malloc及new的性能区别和各自的优势多用小脑和手,少用大脑、眼睛和嘴,会更快地学会编程!
眼过千遍不如手过一遍!
书看千行不如手敲一行!
手敲千行不如单步一行!
单步源代码千行不如单步Debug版对应汇编一行!
单步Debug版对应汇编千行不如单步Release版对应汇编一行!

单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。

VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。

想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
但我又不得不承认:
 有那么些人喜欢或者适合用“先具体再抽象”的方法学习和理解复杂事物;
 而另一些人喜欢或者适合用“先抽象再具体”的方法学习和理解复杂事物。
而我本人属前者。

不要企图依赖输出指针相关表达式...的值【比如printf("%p\n",...);或者cout<<...】来理解指针的本质,
而要依赖调试时的反汇编窗口中的C/C++代码【比如void *p=(void *)(...);】及其对应汇编指令以及内存窗口中的内存地址和内存值来理解指针的本质。


这辈子不看内存地址和内存值;只画链表、指针示意图,画堆栈示意图,画各种示意图,甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗?本人深表怀疑!
这辈子不种麦不收麦不将麦粒拿去磨面;只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头,压面条,烤面包,……能从本质上理解面粉、理解面食吗?本人深表怀疑!!

提醒:
“学习用汇编语言写程序”

“VC调试(TC或BC用TD调试)时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习C和汇编的对应关系。”
不是一回事!

不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!

有人说一套做一套,你相信他说的还是相信他做的?
其实严格来说这个世界上古往今来所有人都是说一套做一套,不是吗?

无profiler不要谈效率!!尤其在这个云计算、虚拟机、模拟器、CUDA、多核 、多级cache、指令流水线、多种存储介质、……满天飞的时代!

#3


File: C:\windows_2000_source_code\win2k\private\sdktools\imagehlp\crt.c

     36: void * __cdecl
     37: malloc(
     38:     size_t sz
     39:     )
     40: {
     41: 
     42:     return RtlAllocateHeap( RtlProcessHeap(), 0, sz );
     43: 
     44: }


File: C:\windows_2000_source_code\win2k\private\ntos\rtl\heap.c

     86: RtlDebugCreateHeap (
     96: RtlDebugDestroyHeap (
    101: RtlDebugAllocateHeap (
    108: RtlDebugFreeHeap (
    115: RtlDebugSizeHeap (
    122: RtlDebugZeroHeap (
    135: RtlpCreateUnCommittedRange (
    140: RtlpDestroyUnCommittedRange (
    146: RtlpInsertUnCommittedPages (
    153: RtlpDestroyHeapSegment (
    158: RtlpExtendHeap (
    191: RtlCreateHeap (
   1133: RtlDestroyHeap (
   1316: RtlAllocateHeap (
   2075: RtlAllocateHeapSlowly (
   2931: RtlFreeHeap (
   3273: RtlFreeHeapSlowly (
   3655: RtlSizeHeap (
   3762: RtlZeroHeap (
   3962: RtlpCreateUnCommittedRange (
   4169: RtlpDestroyUnCommittedRange (
   4227: RtlpInsertUnCommittedPages (
   4422: RtlpFindAndCommitPages (
   4732: RtlpInitializeHeapSegment (
   4959: RtlpDestroyHeapSegment (
   5024: RtlpExtendHeap (
   5312: RtlpCoalesceFreeBlocks (
   5527: RtlpDeCommitFreeBlock (
   5849: RtlpInsertFreeBlock (
   6008: RtlpGetExtraStuffPointer (
   6070: RtlpGetSizeOfBigBlock (
   6117: RtlpCheckBusyBlockTail (

#4


File: C:\windows_2000_source_code\win2k\private\windows\base\client\gmem.c

     42: HGLOBAL
     43: WINAPI
     44: GlobalAlloc(
     45:     UINT uFlags,
     46:     SIZE_T dwBytes
     47:     )
     48: {
     49:     PBASE_HANDLE_TABLE_ENTRY HandleEntry;
     50:     HANDLE hMem;
     51:     LPSTR p;
     52:     ULONG Flags;
     53: 
     54:     if (uFlags & ~GMEM_VALID_FLAGS) {
     55:         SetLastError( ERROR_INVALID_PARAMETER );
     56:         return( NULL );
     57:         }
     58: 
     59:     Flags = 0;
     60:     if (uFlags & GMEM_ZEROINIT) {
     61:         Flags |= HEAP_ZERO_MEMORY;
     62:         }
     63: 
     64:     if (!(uFlags & GMEM_MOVEABLE)) {
     65:         if (uFlags & GMEM_DDESHARE) {
     66:             Flags |= BASE_HEAP_FLAG_DDESHARE;
     67:             }
     68: 
     69:         p = RtlAllocateHeap( BaseHeap,
     70:                              MAKE_TAG( GMEM_TAG ) | Flags,
     71:                              dwBytes ? dwBytes : 1
     72:                            );
     73: 
     74:         if (p == NULL) {
     75:             SetLastError( ERROR_NOT_ENOUGH_MEMORY );
     76:             }
     77: 
     78:         return p;
     79:         }
     80: 
     81:     p = NULL;
     82:     RtlLockHeap( BaseHeap );
     83:     Flags |= HEAP_NO_SERIALIZE | HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVEABLE;
     84:     try {
     85:         HandleEntry = (PBASE_HANDLE_TABLE_ENTRY)RtlAllocateHandle( &BaseHeapHandleTable, NULL );
     86:         if (HandleEntry == NULL) {
     87:             SetLastError( ERROR_NOT_ENOUGH_MEMORY );
     88:             goto Fail;
     89:             }
     90: 
     91:         hMem = (HANDLE)&HandleEntry->Object;
     92:         if (dwBytes != 0) {
     93:             p = (LPSTR)RtlAllocateHeap( BaseHeap, MAKE_TAG( GMEM_TAG ) | Flags, dwBytes );
     94:             if (p == NULL) {
     95:                 HandleEntry->Flags = RTL_HANDLE_ALLOCATED;
     96:                 RtlFreeHandle( &BaseHeapHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry );
     97:                 HandleEntry = NULL;
     98:                 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
     99:                 }
    100:             else {
    101:                 RtlSetUserValueHeap( BaseHeap, HEAP_NO_SERIALIZE, p, hMem );
    102:                 }
    103:             }
    104: Fail:   ;
    105:         }
    106:     except (EXCEPTION_EXECUTE_HANDLER) {
    107:         BaseSetLastNTError( GetExceptionCode() );
    108:         }
    109: 
    110:     RtlUnlockHeap( BaseHeap );
    111: 
    112:     if (HandleEntry != NULL) {
    113:         HandleEntry->Object = p;
    114:         if (p != NULL) {
    115:             HandleEntry->Flags = RTL_HANDLE_ALLOCATED;
    116:             }
    117:         else {
    118:             HandleEntry->Flags = RTL_HANDLE_ALLOCATED | BASE_HANDLE_DISCARDED;
    119:             }
    120: 
    121:         if (uFlags & GMEM_DISCARDABLE) {
    122:             HandleEntry->Flags |= BASE_HANDLE_DISCARDABLE;
    123:             }
    124: 
    125:         if (uFlags & GMEM_MOVEABLE) {
    126:             HandleEntry->Flags |= BASE_HANDLE_MOVEABLE;
    127:             }
    128: 
    129:         if (uFlags & GMEM_DDESHARE) {
    130:             HandleEntry->Flags |= BASE_HANDLE_SHARED;
    131:             }
    132: 
    133:         p = (LPSTR)hMem;
    134:         }
    135: 
    136:     return( (HANDLE)p );
    137: }

#5


引用 4 楼 zhao4zhong1 的回复:

老赵幸苦了,劳烦再把HeapAlloc和malloc的代码贴一下,然后大粉给你 HeapAlloc和GlobalAlloc及malloc及new的性能区别和各自的优势

#6


malloc的前面已经贴了。
File: C:\windows_2000_source_code\win2k\private\shell\win16\commctrl\mem.c
    192: void NEAR* NEAR HeapAlloc(HHEAP hhp, WORD cb)
    193: {
    194:     void NEAR* pb;
    195:
    196:     _asm {
    197:         push    ds
    198:         mov     ds,hhp
    199:     }
    200:
    201:     pb = (void NEAR*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cb);
    202:
    203:     if (pb)
    204:         ((HEAP NEAR*)0)->cAlloc++;
    205:
    206:     _asm {
    207:         pop     ds
    208:     }
    209:
    210:     return pb;
    211: }

http://bbs.csdn.net/topics/390374955里面有windows_2000_source_code的下载链接

#7


看来malloc还真的不是线程安全的。