1. 首先我们来看HeapAlloc:
HeapAlloc是一个Windows API函数。它用来在指定的堆上分配内存,并且分配后的内存不可移动。(即如果没有连续的空间能满足分配的大小,程序不能将其他零散的 空间利用起来,从而导致分配失败),该分配方法是从一指定地址开始分配,而不像GloabalAlloc是从全局堆上分配,这个有可能是全局,也有可能是 局部。函数原型为:
<span style="font-family:Arial;font-size:14px;">LPVOID
HeapAlloc(
HANDLE hHeap,
DWORD dwFlags,
SIZE_T dwBytes
);</span>
<span style="font-family:Arial;font-size:14px;">hHeap: <span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 28px;">要分配堆的句柄,可以通过</span><a target=_blank target="_blank" href="http://baike.baidu.com/subview/1745173/1745173.htm" style="text-decoration: none; color: rgb(19, 110, 194); line-height: 24px; text-indent: 28px;">HeapCreate</a><span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 28px;">()函数或</span><a target=_blank target="_blank" href="http://baike.baidu.com/subview/1595729/1595729.htm" style="text-decoration: none; color: rgb(19, 110, 194); line-height: 24px; text-indent: 28px;">GetProcessHeap</a><span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 28px;">()函数获得。</span>
dwFlags: <span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 28px;">堆分配时的可选参数,其值可以为以下的一种或多种:</span></span>
<div style="text-indent: 28px;"><span style="font-family:Arial;font-size:14px;color:#333333;"><span style="line-height: 24px;"></span></span><table log-set-param="table_view" class="table-view log-set-param " style="border-collapse: collapse; border-spacing: 0px; margin: 5px 0px; word-wrap: break-word; word-break: break-all; line-height: 22px; color: rgb(0, 0, 0);"><tbody><tr><th height="0" align="left" valign="top" style="margin: 0px; padding: 2px 10px; height: 23px; border: 1px solid rgb(230, 230, 230); text-align: center; background-color: rgb(249, 249, 249);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">值</div></th><th style="margin: 0px; padding: 2px 10px; height: 23px; border: 1px solid rgb(230, 230, 230); text-align: center; background-color: rgb(249, 249, 249);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">意义</div></th></tr><tr><td valign="top" align="left" width="200" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">HEAP_GENERATE_EXCEPTIONS</div></td><td valign="top" align="left" width="475" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">如果分配错误将会<a target=_blank target="_blank" href="http://baike.baidu.com/subview/3139209/3139209.htm" style="text-decoration: none; color: rgb(19, 110, 194);">抛出异常</a>,而不是返回NULL。<a target=_blank target="_blank" href="http://baike.baidu.com/subview/2447561/2447561.htm" style="text-decoration: none; color: rgb(19, 110, 194);">异常值</a>可能是STATUS_NO_MEMORY, 表示获得的<a target=_blank target="_blank" href="http://baike.baidu.com/subview/1658496/1658496.htm" style="text-decoration: none; color: rgb(19, 110, 194);">内存容量</a>不足,或是STATUS_ACCESS_VIOLATION,表示存取不合法。</div></td></tr><tr><td valign="top" align="left" width="200" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">HEAP_NO_SERIALIZE</div></td><td valign="top" align="left" width="475" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">不使用连续存取。</div></td></tr><tr><td valign="top" align="left" width="200" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">HEAP_ZERO_MEMORY</div></td><td valign="top" align="left" width="475" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">将分配的内存全部清零。</div></td></tr></tbody></table></div><span style="font-family:Arial;font-size:14px;">dwBytes: <span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 28px;">要分配堆的字节数。</span>
<span style="color:#ff0000;">其对应的释放空间函数为HeapFree</span>。</span>
<span style="font-family:Arial;font-size:14px;">返回值:</span>
<span style="font-family:Arial;font-size:14px;"><span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 28px;">如果成功分配内存,返回值为一个指向所分配内存块的首地址的(</span><a target=_blank target="_blank" href="http://baike.baidu.com/subview/1004734/15302678.htm" style="text-decoration: none; color: rgb(19, 110, 194); line-height: 24px; text-indent: 28px;">void</a><span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 28px;">*)指针。</span></span>
<span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 28px;"><span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 28px;"><span style="font-family:Arial;font-size:14px;">如果分配内存失败,并且没有指定HEAP_GENERATE_EXCEPTIONS,则返回NULL。</span></span></span>
<span style="font-family:Arial;font-size:14px;"><span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 2em;">如果指定了HEAP_GENERATE_EXCEPTIONS,则</span><a target=_blank target="_blank" href="http://baike.baidu.com/subview/3139209/3139209.htm" style="line-height: 24px; text-indent: 2em; text-decoration: none; color: rgb(19, 110, 194);">抛出异常</a><span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 2em;">,而不返回NULL:</span><span style="line-height: 24px; white-space: nowrap; margin-left: 2px; color: rgb(51, 102, 204); cursor: pointer; padding: 0px 2px; position: relative; vertical-align: baseline; top: -0.5em;">[1]</span><a target=_blank class="anchor-inline " name="ref_[1]_5373191" style="text-indent: 2em; background-color: rgb(240, 240, 240); color: rgb(19, 110, 194); position: relative; display: inline; top: -50px; line-height: 0;"> </a></span>
<span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 28px;"><span style="color: rgb(51, 51, 51); line-height: 24px; text-indent: 28px;"><span style="font-family:Arial;font-size:14px;"></span></span></span><table log-set-param="table_view" width="99%" class="table-view log-set-param " style="border-collapse: collapse; border-spacing: 0px; margin: 5px 0px; word-wrap: break-word; word-break: break-all; line-height: 22px; color: rgb(0, 0, 0);"><tbody><tr><th style="margin: 0px; padding: 2px 10px; height: 23px; border: 1px solid rgb(230, 230, 230); text-align: center; background-color: rgb(249, 249, 249);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">异常代码</div></th><th height="0" align="center" valign="top" style="margin: 0px; padding: 2px 10px; height: 23px; border: 1px solid rgb(230, 230, 230); text-align: center; background-color: rgb(249, 249, 249);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">描述</div></th></tr><tr><td style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;"><strong>STATUS_NO_MEMORY</strong></div></td><td align="center" valign="top" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">由于缺少可用内存或者是堆损坏导致分配失败。</div></td></tr><tr><td style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;"><strong>STATUS_ACCESS_VIOLATION</strong></div></td><td align="center" valign="top" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">由于堆损坏或者是不正确的函数参数导致分配失败。.</div></td></tr></tbody></table>例如:
<pre name="code" class="cpp">plfTable = (PIP_INTERFACE_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PIP_INTERFACE_INFO));
// ... (your operations)
HeapFree(GetProcessHeap(), 0, plfTable); // 使用完毕后释放堆
注:PIP_INTERFACE_INFO结构包含了与IPv4网络接口适配器,在本地系统上启用的列表
<span style="font-family:Arial;font-size:14px;">2. GlobalAlloc
</span>
<span style="font-family:Arial;font-size:14px;"><span style="color: rgb(51, 51, 51); font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 28px;">GlobalAlloc是一个Windows API函数。该函数从堆中分配一定数目的字节数。Win32</span><a target=_blank target="_blank" href="http://baike.baidu.com/view/404423.htm" style="text-decoration: none; color: rgb(19, 110, 194); font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 28px;">内存管理器</a><span style="color: rgb(51, 51, 51); font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 28px;">并不提供相互分开的局部和全局堆。提供这个函数只是为了与16位的Windows相兼容。简称全局堆分配</span>
</span>
<span style="font-family:Arial;font-size:14px;"><span style="color: rgb(51, 51, 51); font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 28px;">HGLOBALGlobalAlloc(
UINTuFlags, //分配属性(方式)
DWORDdwBytes //分配的字节数
);</span></span><a target=_blank class="anchor-inline " name="ref_[1]_1265279" style="font-family: arial, 宋体, sans-serif; text-indent: 2em; background-color: rgb(240, 240, 240); color: rgb(19, 110, 194); position: relative; display: inline; top: -50px; font-size: 0px; line-height: 0;"> </a>
<span style="font-family:Arial;font-size:14px;"><span style="color:#ff0000;">返回值是内存对象的句柄,用函数GlobalLock可将句柄转化为指针;</span></span>
<span style="font-family:Arial;font-size:14px;"></span><table log-set-param="table_view" class="table-view log-set-param " width="0" style="color: rgb(0, 0, 0); border-collapse: collapse; border-spacing: 0px; margin: 5px 0px; word-wrap: break-word; word-break: break-all; font-size: 12px; line-height: 22px; font-family: arial, 宋体, sans-serif;"><tbody><tr><th width="0" height="0" align="left" valign="middle" colspan="0" style="margin: 0px; padding: 2px 10px; height: 23px; border: 1px solid rgb(230, 230, 230); text-align: center; background-color: rgb(249, 249, 249);">标识</th><th style="margin: 0px; padding: 2px 10px; height: 23px; border: 1px solid rgb(230, 230, 230); text-align: center; background-color: rgb(249, 249, 249);">意义</th></tr><tr><td width="115" align="left" valign="middle" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);">GHND</td><td valign="top" align="left" width="551" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);">为GMEM_MOVEABLE 和 GMEM_ZEROINIT的组合.</td></tr><tr><td width="115" align="left" valign="middle" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);">GMEM_FIXED</td><td valign="top" align="left" width="551" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);">分配固定的内存,返回值是一个<a target=_blank target="_blank" href="http://baike.baidu.com/view/159417.htm" style="text-decoration: none; color: rgb(19, 110, 194);">指针</a>.</td></tr><tr><td width="115" align="left" valign="middle" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);">GMEM_MOVEABLE</td><td valign="top" align="left" width="551" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);"><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">分配可移动的内存,在Win32中内存块在<a target=_blank target="_blank" href="http://baike.baidu.com/view/138684.htm" style="text-decoration: none; color: rgb(19, 110, 194);">物理内存</a>中是不可移动的,但在缺省堆中可以. 返回值是该内存对象的<a target=_blank target="_blank" href="http://baike.baidu.com/view/194921.htm" style="text-decoration: none; color: rgb(19, 110, 194);">句柄</a>,可使用函数 GlobalLock 将该句柄转换为一个<a target=_blank target="_blank" href="http://baike.baidu.com/view/159417.htm" style="text-decoration: none; color: rgb(19, 110, 194);">指针</a>.</div><div class="para" style="color: rgb(51, 51, 51); margin: 0px; line-height: 24px;">这个标识不能与 GMEM_FIXED 组合使用.</div></td></tr><tr><td width="115" align="left" valign="middle" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);">GMEM_ZEROINIT</td><td valign="top" align="left" width="551" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);">将所申请内存初始化为0.</td></tr><tr><td width="115" align="left" valign="middle" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);">GPTR</td><td valign="top" align="left" width="551" style="margin: 0px; padding: 2px 10px; height: 22px; border: 1px solid rgb(230, 230, 230);">为GMEM_FIXED和GMEM_ZEROINIT组合.</td></tr></tbody></table>
<span style="font-family:Arial;font-size:14px;">返回值:</span>
<span style="color: rgb(51, 51, 51); font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 2em;">若函数调用成功,则返回一个新分配的内存对象的</span><a target=_blank target="_blank" href="http://baike.baidu.com/view/194921.htm" style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 2em; text-decoration: none; color: rgb(19, 110, 194);">句柄</a>
<span style="color: rgb(51, 51, 51); font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 2em;">若函数调用失败,则返回</span><a target=_blank target="_blank" href="http://baike.baidu.com/view/329484.htm" style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 2em; text-decoration: none; color: rgb(19, 110, 194);">NULL</a><span style="color: rgb(51, 51, 51); font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 2em;">。可调用</span><a target=_blank target="_blank" href="http://baike.baidu.com/view/1730168.htm" style="font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 2em; text-decoration: none; color: rgb(19, 110, 194);">GetLastError</a><span style="color: rgb(51, 51, 51); font-family: arial, 宋体, sans-serif; font-size: 14px; line-height: 24px; text-indent: 2em;">以获得更多错误信息。</span>
<div style="text-indent: 28px;"><span style="font-family:arial, 宋体, sans-serif;color:#333333;"><span style="font-size: 14px; line-height: 24px;">
</span></span></div><span style="font-family:Arial;font-size:14px;">一般情况下我们在编程的时候,给应用程序分配的内存都是可以移动的或者是可以丢弃的,这样能使有限的内存资源充分利用,所以,在某一个时候我们分配的那块 内存的地址是不确定的,因为他是可以移动的,所以得先锁定那块内存块,这儿应用程序需要调用API函数GlobalLock函数来锁定内存句柄,例如 lpMem=GlobalLock(hMem);返回指向内存块的指针,这样应用程序才能存取这块内存。所以我们在使用GlobalAllock时,通常搭配使用GlobalLock。当然在不使用内存时,一定记得使用 GlobalUnlock,否则被锁定的内存块一直不能被其他变量使用。
<span style="color:#ff0000;">GlobalAlloc对应的释放空间的函数为GlobalFree</span>。</span>
<span style="font-family:Arial;font-size:14px;">
3. LocalAlloc:该函数用于从局部堆(进程内存)中分配内存供程序使用,函数原型为:
</span>
<pre name="code" class="cpp"><span style="font-family:Arial;font-size:14px;">HLOCAL LocalAlloc(
UINT uFlags,
SIZE_T uBytes
);</span>
参数同GlobalAlloc。
在16位Windows中是有区别的,因为在16位windows用一个全局堆和局部堆来管理内存,每一个应用程序或dll装入内存时,代码段被装入全局 堆,而系统又为每个实例从全局堆中分配了一个64kb的数据段作为该实例的局部堆,用来存放应用程序的堆栈和所有全局或静态变量。而 LocalAlloc/GlobalAlloc就是分别用于在局部堆或全局堆中分配内存。
由于每个进程的局部堆很小,所以在局部堆中分配内存会受到空间的限制。但这个堆是每个进程私有的,相对而言分配数据较安全,数据访问出错不至于影响到整个系统。
而在全局堆中分配的内存是为各个进程共享的,每个进程只要拥有这个内存块的句柄都可以访问这块内存,但是每个全局内存空间需要额外的内存开销,造成分配浪费。而且一旦发生严重错误,可能会影响到整个系统的稳定。
不过在Win32中,每个进程都只拥有一个省缺的私有堆,它只能被当前进程访问。应用程序也不可能直接访问系统内存。所以在Win32中全局堆和局部堆都指向进程的省缺堆,用LocalAlloc/GlobalAlloc分配内存没有任何区别,甚至LocalAlloc分配的内存可以被 GlobalFree释放掉。所以在Win32下编程,无需注意Local和Global的区别,一般的内存分配都等效于 HeapAlloc(GetProcessHeap(),...)。
LocalAlloc对应的释放函数为LocalFree。
<span style="font-family:Arial;font-size:14px;"><span style="color:#ff0000;"></span></span><div class="para" style="color: rgb(51, 51, 51); margin: 15px 0px 5px; text-indent: 2em; line-height: 24px; font-family: arial, 宋体, sans-serif; font-size: 14px;">该函数用局部内存对象的分配(全局内存对象的分配使用函数<a target=_blank target="_blank" href="http://baike.baidu.com/subview/1265279/1265279.htm" style="text-decoration: none; color: rgb(19, 110, 194);">GlobalAlloc</a>)。</div><div class="para" style="color: rgb(51, 51, 51); margin: 15px 0px 5px; text-indent: 2em; line-height: 24px; font-family: arial, 宋体, sans-serif; font-size: 14px;">如果堆中没有充足的自由空间去满足我们的需求,LocalAlloc返回NULL。因为NULL被使用去表明一个错误,<a target=_blank target="_blank" href="http://baike.baidu.com/subview/1499823/1499823.htm" style="text-decoration: none; color: rgb(19, 110, 194);">虚拟地址</a>zero从不被分配。因此,很容易去检测NULL<a target=_blank target="_blank" href="http://baike.baidu.com/view/159417.htm" style="text-decoration: none; color: rgb(19, 110, 194);">指针</a>的使用。</div><div class="para" style="color: rgb(51, 51, 51); margin: 15px 0px 5px; text-indent: 2em; line-height: 24px; font-family: arial, 宋体, sans-serif; font-size: 14px;">如果函数成功的话,它至少会分配我们指定大小的内存。如果分配给我们的数量多于我们指定的话,这个进程能使用整个数量的内存。</div><div class="para" style="color: rgb(51, 51, 51); margin: 15px 0px 5px; text-indent: 2em; line-height: 24px; font-family: arial, 宋体, sans-serif; font-size: 14px;"><span style="text-indent: 2em;">可以使用</span><a target=_blank target="_blank" href="http://baike.baidu.com/subview/5605308/5647289.htm" style="text-indent: 2em; text-decoration: none; color: rgb(19, 110, 194);">LocalSize</a><span style="text-indent: 2em;">函数去检测被分配的字节数。</span></div><div class="para" style="color: rgb(51, 51, 51); margin: 15px 0px 5px; text-indent: 2em; line-height: 24px; font-family: arial, 宋体, sans-serif; font-size: 14px;"><span style="text-indent: 2em;">可以使用</span><a target=_blank target="_blank" href="http://baike.baidu.com/subview/8552073/8500588.htm" style="text-indent: 2em; text-decoration: none; color: rgb(19, 110, 194);">LocalFree</a><span style="text-indent: 2em;">函数去释放这段内存。</span></div><div class="para" style="color: rgb(51, 51, 51); margin: 15px 0px 5px; text-indent: 2em; line-height: 24px; font-family: arial, 宋体, sans-serif; font-size: 14px;">对于分配的可移动内存、可删除内存读取前需加锁(<a target=_blank target="_blank" href="http://baike.baidu.com/subview/2248734/2248734.htm" style="color: rgb(19, 110, 194);">相关函数</a><a target=_blank target="_blank" href="http://baike.baidu.com/view/4660268.htm" style="text-decoration: none; color: rgb(19, 110, 194);">LocalLock</a>)否则将无法正常读取,读取完成后需解锁(相关函数LocalUnlock)否则无法使用LocalFree函数来释放内存。</div>
<span style="font-family:Arial;font-size:14px;">4. VirtualAlloc</span>
<span style="font-family:Arial;font-size:14px;">该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页,如果用于内存分配的话,并且分配类型未指定MEM_RESET,则系统将自动设置为0;其函数原型:
</span><pre name="code" class="cpp"><span style="font-family:Arial;font-size:14px;">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
);</span>
VirtualAlloc可以通过并行多次调用提交一个区域的部分或全部来保留一个大的内存区域。多重调用提交同一块区域不会引起失败。这使得一个应用程 序保留内存后可以随意提交将被写的页。当这种方式不在有效的时候,它会释放应用程序通过检测被保留页的状态看它是否在提交调用之前已经被提交。
VirtualAlloc对应的释放函数为VirtualFree。
<span style="font-family:Arial;font-size:14px;">
5.Malloc:</span>
<span style="font-family:Arial;font-size:14px;">malloc与free是C++/C语言的标准库函数,可用于申请动态内存和释放内存。<span style="color:#ff0000;">对于非内部数据类型的对象而言,光用 malloc/free无法满足动态对象的要求</span>。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。</span>
<span style="font-family:Arial;font-size:14px;">
6.New:</span>
<span style="font-family:Arial;font-size:14px;">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指针。
</span><p><span style="font-family:Arial;font-size:14px;">用Win32SDK编程可以有多种方法分配内存
1.GlobalAlloc
2.HeapAlloc
3.LocalAlloc
4.VirtualAlloc(Ex)
以及标准C/C++中的
5.malloc
6.calloc
7.new
用不同的方法申请了64KB大小空间,以下是返回的地址值(WindowsXPsp2):
LocalAlloc: 00143060
GlobalAlloc: 00143060
HeapAlloc: 00143060
VirtualAlloc: 00390000
malloc: 00410048
new: 00410048
可见LocalAlloc和GlobalAlloc的地址和堆分配是一样的,
MSDN也写着前两个函数只是为兼容16位版本而保留的,所以不建议再使用了.
VirtualAlloc分配比较复杂,可以设置分配内存的属性.
malloc和new的结果相同.
这样就共有3种结果了.</span></p><p><span style="font-family:Arial;font-size:14px;">我简单的说几句。
调用关系如下 new->malloc->HeapAlloc->VirtualAlloc->驱动程序的_PageAlloc。
上面的调用关系是一般的WIN32编译器的调用顺序。
其中HeapAlloc已经实现了malloc的那些小块内存管理,以Heap开头的有一系列函数,你会发现它与malloc/free等可以对应起来。
但是Borland和VC编译器稍有不同,它们选择了自己实现了malloc,而不是直接对Heap*函数做了简单包装。
当然,有些C++编译器new并不是先调用malloc,然后调用构造函数,但总的来说,内存的调用顺序如上。
LocalAlloc和GlobalAlloc是遗留函数。</span></p><p><span style="font-family:Arial;font-size:14px;">在WindowsXP中跟踪了一下:
malloc(msvcrt.malloc)和new(msvcrt.??2@YAPAXI@Z)的函数体大部分(主要是核心部分)是相同的,所以结果分配也是相同的.
这两个函数都是调用kernel32.HeapAlloc实现的.
以下是我跟踪出来的详细调用关系:
msvcrt.malloc => kernel32.HeapAlloc(ntdll.RtlAllocateHeap)
msvcrt.??2@YAPAXI@Z => kernel32.HeapAlloc(ntdll.RtlAllocateHeap)
kernel32.LocalAlloc => ntdll.RtlAllocateHeap
kernel32.GlobleAlloc => ntdll.RtlAllocateHeap
kernel32.HeapAlloc == ntdll.RtlAllocateHeap
kernel32.VirtualAlloc => kernel32.VirtualAllocEx
kernel32.VirtualAllocEx=> ntdll.NtAllocateVirtualMemory
ntdll.RtlAllocateHeap => ntdll.NtAllocateVirtualMemory
ntdll.NtAllocateVirtualMemory => ntdll.KiFastSystemCall
ntdll.KiFastSystemCall => sysenter指令 (0F34)
(注意kernel32中实际没有HeapAlloc的入口地址,而是直接映射到ntdll.RtlAllocateHeap的入口)</span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;">弄清楚这个问题首先要了解VirtualCopy和VirtualAlloc这2个函数的实现和目的,以及wince下动态虚拟内存映射和静态虚拟内存映射。
先说VirtualAlloc 和VirtualCopy
VirtualAlloc 首先会从我们的虚拟地址空间中申请(或者说预留)一块虚拟空间,准备接下来要用它。注意此时,可用的物理内存并没有减少,只是虚拟地址少了一块可用的区域。
真正把这块之前reserved的虚拟空间映射到物理的内存区域就是由VirtualCopy来干的,此时,MMU的页表就会增加一个entry,来表示物理--虚拟的映射关系。</span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;">在没有C运行库可用的时候,要用VirtualAlloc来申请内存。
另外,VirtualAlloc还可对申请的内存有许多的控制。
1、可以保留地址空间但不是及分配内存,在需要的时候再分配;
2、可以声明分配的内存不使用分页;
3、可以指定内存在尽可能高的地址上分配;
4、指定内存的读、写、执行属性和内存保护;
5、禁止所分配内存被高速缓存。
等。</span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><span style="font-family:Arial;font-size:14px;"> </span></p><p><strong><span style="font-family:Arial;font-size:14px;"><span style="color:maroon;">1.</span> <span style="color:maroon;">背景</span></span></strong></p><p><span style="font-family:Arial;font-size:14px;">最近,我在把 PC 上的扫描仪驱动源码移植到 Window CE 系统中,遇到了内存分配的问题。我在 CE 进程中,要一次性分配高达 40M 的内存大小时就提示失败,说内存不足,可是内存是 512M 的肯定足够。本来对内存分配不甚了解,苦苦折腾,总算解决。再此做个 Windows CE 的内存分配的总结。一来是我温故知新,二来供他人参考之用。</span></p><p><strong><span style="font-family:Arial;font-size:14px;"><span style="color:maroon;">2. WCE</span> <span style="color:maroon;">内存简介</span></span></strong></p><p><span style="font-family:Arial;font-size:14px;">在进入主题之前,我想有必要简要了解下 WCE 的内存(详细了解可以参看有关书籍)。</span></p><p><strong><span style="font-family:Arial;font-size:14px;">2.1 、 WCE 内存结构</span></strong></p><p><span style="font-family:Arial;font-size:14px;">Windows CE 是一个保护模式的操作系统,每个进程的地址空间都是相对独立的,因此程序的访问只能使用虚拟内存。 Windows CE 对整个系统实现了一个线性的 32 位( 2 <sup>32 </sup>,即 4GB )的虚拟地址空间。</span></p><p><span style="font-family:Arial;font-size:14px;">Windows CE.net 只能管理 512MB 的物理内存和 4GB 大小的虚拟地址空间。这 4GB 的虚拟地址空间被分为 2 个的 2GB 的区域,一个是 2GB 的内核空间(程序无法访问,以保证系统的安全),一个是 2GB 的用户空间。用户空间又被划分为 64 个 32MB 的槽, Windows CE 系统最多同时可以运行 32 个进程,每个进程都有它自己受保护的、 32MB 的地址空间(而 Windows XP 拥有 2GB 的私有地址空间),同时也受到了 32MB 空间大小的限制。</span></p><p><strong><span style="font-family:Arial;font-size:14px;">2.2 、堆和栈</span></strong></p><p><span style="font-family:Arial;font-size:14px;"> 堆是一段连续的相对较大的虚拟地址空间。堆具有以下特点:</span></p><p><span style="font-family:Arial;font-size:14px;">◆堆是向高地址扩展的数据结构</span></p><p><span style="font-family:Arial;font-size:14px;">◆一般由程序员分配释放, 若程序员不释放,程序结束时可能由 OS 回收 。在堆中分别内存是以字节为单位。如 malloc 、 new 等。</span></p><p><span style="font-family:Arial;font-size:14px;">◆默认堆</span></p><p><span style="font-family:Arial;font-size:14px;">当运用程序启动时,内核在进程地址所在空间中为进程分配了一个 192K 大小的虚拟地址空间作为默认堆使用。但是并不立刻提交物理内存。如果在运行当中192KB 不能满足需求,那么内核会在进程地址空间中重新查找一个足够大小的空闲的地址空间,然后复制原来堆的数据,最后释放原来的堆所占的地址空间。这是因为默认的堆的高地址处还有栈,所以必须重新分配一个。</span></p><p><span style="font-family:Arial;font-size:14px;">◆优点</span></p><p><span style="font-family:Arial;font-size:14px;">堆的优点是能在一定范围内减少内存碎片。</span></p><p><span style="font-family:Arial;font-size:14px;">◆缺点</span></p><p><span style="font-family:Arial;font-size:14px;">Windows CE.NET 的堆有明显的缺点,不同于其它 Windows 操作系统下的堆管理,在 Windows CE.NET 的堆中创建的内存块不能够移动,多次创建内存块、释放内存块会产生内存碎块,这样的话当需要分配一个大一点的连续的内存块时,本来空闲的内存块加起来足够用,但是这些内存块是分隔的,不符合要求。像Windows 2000 或 98 的内核会频繁的移动分散的正使用的内存块,使它们聚集在一起。这也是为什么有时需要句柄而不用指针的原因。由于 Windows CE.NET 的堆的缺点,开发者如果要频繁的在堆中创建、释放内存块的话,最好自己创建一个单独的堆,而不用默认的堆。</span></p><p><span style="font-family:Arial;font-size:14px;">栈具有如下特点:</span></p><p><span style="font-family:Arial;font-size:14px;">◆栈是向低地址扩展的数据结构</span></p><p><span style="font-family:Arial;font-size:14px;">◆栈由编译器自动分配释放 ,如一个函数的参数和局部变量都在栈上。</span></p><p><span style="font-family:Arial;font-size:14px;">◆栈也是一段连续的虚拟地址空间,和堆相比空间要小的多,它是专为函数使用的。</span></p><p><span style="font-family:Arial;font-size:14px;">◆修改栈大小</span></p><p><span style="font-family:Arial;font-size:14px;">可以在编译器设置修改栈的大小,或者在创建线程时指定栈的大小。如果采用在编译链接时修改大小,那么所有栈的大小都会改变。</span></p><p><strong><span style="font-family:Arial;font-size:14px;">2.4 内存映射文件</span></strong></p><p><span style="font-family:Arial;font-size:14px;">内存映射文件能保留一个虚拟地址空间,并提交物理内存。内存映射文件常用于:</span></p><p><span style="font-family:Arial;font-size:14px;">◆映射大容量文件</span></p><p><span style="font-family:Arial;font-size:14px;">运用程序不必在访问文件之前申请很大的内存作为读取文件的缓存区。</span></p><p><span style="font-family:Arial;font-size:14px;">◆进程间通信</span></p><p><span style="font-family:Arial;font-size:14px;">也是进程通信间的主要手段,其他进程间的通信机制都是基于内存映射文件来完成的。</span></p><p><span style="font-family:Arial;font-size:14px;">◆申请大容量的虚拟地址空间</span></p><p><span style="font-family:Arial;font-size:14px;"> 内存映射文件在全局地址空间内( 0x420000 到 0x7FFFFFFF )分配。</span></p><p><strong><span style="font-family:Arial;font-size:14px;">2.5 申请效率的比较:</span></strong></p><p><span style="font-family:Arial;font-size:14px;">◆堆是由 malloc 、 new 等分配的内存,一般速度比较慢,而且容易产生内存碎片 , 不过用起来最方便。</span></p><p><span style="font-family:Arial;font-size:14px;">◆栈由系统自动分配,速度较快。但程序员是无法控制的。</span></p><p><span style="font-family:Arial;font-size:14px;">◆在 WINDOWS 下,最好的方式是用 VirtualAlloc 分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。</span></p><p><strong><span style="font-family:Arial;font-size:14px;"><span style="color:maroon;">3</span> <span style="color:maroon;">、比较分配内存的各种方法</span></span></strong></p><p><span style="font-family:Arial;font-size:14px;">看看这里: <a target=_blank href="http://msdn.microsoft.com/en-us/library/aa366533%28VS.85%29.aspx" style="color:rgb(202, 0, 0);"><span style="color:rgb(128, 0, 128);">http://msdn.microsoft.com/en-us/library/aa366533(VS.85).aspx</span></a></span></p><p align="left"><strong><span style="font-family:Arial;font-size:14px;">Comparing Memory Allocation Methods</span></strong></p><p align="left"><span style="font-family:Arial;font-size:14px;">The following is a brief comparison of the various memory allocation methods:</span></p><ul type="disc"><li><a target=_blank href="http://msdn.microsoft.com/en-us/library/ms692727%28VS.85%29.aspx" style="color:rgb(202, 0, 0);"><strong><span style="color:rgb(0, 51, 204);"><span style="font-family:Arial;font-size:14px;">CoTaskMemAlloc</span></span></strong></a></li><li><a target=_blank href="http://msdn.microsoft.com/en-us/library/aa366574%28VS.85%29.aspx" style="color:rgb(202, 0, 0);"><strong><span style="color:rgb(0, 51, 204);"><span style="font-family:Arial;font-size:14px;">GlobalAlloc</span></span></strong></a></li><li><a target=_blank href="http://msdn.microsoft.com/en-us/library/aa366597%28VS.85%29.aspx" style="color:rgb(202, 0, 0);"><strong><span style="color:rgb(0, 51, 204);"><span style="font-family:Arial;font-size:14px;">HeapAlloc</span></span></strong></a></li><li><a target=_blank href="http://msdn.microsoft.com/en-us/library/aa366723%28VS.85%29.aspx" style="color:rgb(202, 0, 0);"><strong><span style="color:rgb(0, 51, 204);"><span style="font-family:Arial;font-size:14px;">LocalAlloc</span></span></strong></a></li><li><strong><span style="font-family:Arial;font-size:14px;">malloc</span></strong></li><li><strong><span style="font-family:Arial;font-size:14px;">new</span></strong></li><li><a target=_blank href="http://msdn.microsoft.com/en-us/library/aa366887%28VS.85%29.aspx" style="color:rgb(202, 0, 0);"><strong><span style="color:rgb(0, 51, 204);"><span style="font-family:Arial;font-size:14px;">VirtualAlloc</span></span></strong></a></li></ul><p align="left"><span style="font-family:Arial;font-size:14px;">Although the <strong>GlobalAlloc</strong> , <strong>LocalAlloc</strong> , and <strong>HeapAlloc</strong> functions ultimately allocate memory from the same heap, each provides a slightly different set of functionality. For example, <strong>HeapAlloc</strong> can be instructed to raise an exception if memory could not be allocated, a capability not available with <strong>LocalAlloc</strong> . <strong>LocalAlloc</strong> supports allocation of handles which permit the underlying memory to be moved by a reallocation without changing the handle value, a capability not available with <strong>HeapAlloc</strong> .</span></p><p align="left"><span style="font-family:Arial;font-size:14px;">Starting with 32-bit Windows, <strong>GlobalAlloc</strong> and <strong>LocalAlloc</strong> are implemented as wrapper functions that call <strong>HeapAlloc</strong> using a handle to the process's default heap. Therefore, <strong>GlobalAlloc</strong> and <strong>LocalAlloc</strong> have greater overhead than <strong>HeapAlloc</strong> .</span></p><p align="left"><span style="font-family:Arial;font-size:14px;">Because the different heap allocators provide distinctive functionality by using different mechanisms, you must free memory with the correct function. For example, memory allocated with <strong>HeapAlloc</strong> must be freed with <a target=_blank href="http://msdn.microsoft.com/en-us/library/aa366701%28VS.85%29.aspx" style="color:rgb(202, 0, 0);"><strong><span style="color:rgb(0, 51, 204);">HeapFree</span> </strong></a>and not <a target=_blank href="http://msdn.microsoft.com/en-us/library/aa366730%28VS.85%29.aspx" style="color:rgb(202, 0, 0);"><strong><span style="color:rgb(0, 51, 204);">LocalFree</span> </strong></a>or <a target=_blank href="http://msdn.microsoft.com/en-us/library/aa366579%28VS.85%29.aspx" style="color:rgb(202, 0, 0);"><strong><span style="color:rgb(0, 51, 204);">GlobalFree</span> </strong></a>. Memory allocated with <strong>GlobalAlloc</strong> or <strong>LocalAlloc</strong> must be queried, validated, and released with the corresponding global or local function.</span></p><p align="left"><span style="font-family:Arial;font-size:14px;">The <strong>VirtualAlloc</strong> function allows you to specify additional options for memory allocation. However, its allocations use a page granularity, so using <strong>VirtualAlloc</strong> can result in higher memory usage.</span></p><p align="left"><span style="font-family:Arial;font-size:14px;">The <strong>malloc</strong> function has the disadvantage of being run-time dependent. The <strong>new</strong> operator has the disadvantage of being compiler dependent and language dependent.</span></p><p align="left"><span style="font-family:Arial;font-size:14px;">The <a target=_blank href="http://msdn.microsoft.com/en-us/library/ms692727%28VS.85%29.aspx" style="color:rgb(202, 0, 0);"><strong><span style="color:rgb(0, 51, 204);">CoTaskMemAlloc</span> </strong></a>function has the advantage of working well in either C, C++, or Visual Basic. It is also the only way to share memory in a COM-based application, since MIDL uses <strong>CoTaskMemAlloc</strong> and <a target=_blank href="http://msdn.microsoft.com/en-us/library/ms680722%28VS.85%29.aspx" style="color:rgb(202, 0, 0);"><strong><span style="color:rgb(0, 51, 204);">CoTaskMemFree</span> </strong></a>to marshal memory.</span></p><p><strong><span style="font-family:Arial;font-size:14px;"><span style="color:maroon;">4</span> <span style="color:maroon;">、</span> <span style="color:maroon;">WCE</span> <span style="color:maroon;">中申请大容量内存</span></span></strong></p><p><span style="font-family:Arial;font-size:14px;">WCE 运用程序的地址空间局限于 32MB 所引起的另外一个问题是如何分配大类型内存块。那么如何才能突破 32M 限制呢?</span></p><p align="center"><span style="font-family:Arial;font-size:14px;">看看我的测试程序,用了不同的分配内存的方法来分配最大的内存。点击“ Alocates Memory ”开始分配,如图 4-1 可以看出,除了用内存映射外,其他的都无法突破 32M ,哪怕 VirtualAlloc 也不行。如果多次“ Alocates Memory ”你会发现内存映射文件能分配到的内内存越来越小,这我还没搞明白是什么原因,可能是内存碎片引起的。 <img src="http://p.blog.csdn.net/images/p_blog_csdn_net/benkaoya/EntryImages/20081216/1633650175907031250.jpg" alt="" width="512" height="384" /></span></p><p align="center"><span style="font-family:Arial;font-size:14px;">图 4-1 WCE 中各种方法分配最大内存</span></p><p><span style="font-family:Arial;font-size:14px;">5 、总结</span></p><p><span style="font-family:Arial;font-size:14px;"> 写了好久,感觉写得好乱…… ^_^ 。但不管了,先发表,以后慢慢修改。如有错误,恳请赐教!</span></p><span style="font-family:Arial;font-size:14px;">
</span>