关于使用delete(free)释放内存的疑问

boolean6199 2002-11-12 07:14:06
imfree使用malloc(new)申请内存,当申请的内存是一个数组时,数组的大小在编译时不一定确定,而释放该内存块时只需要简单地将指针传给free(delete) ,那么free如何知道该释放多少的空间呢,c/c++是否在内存分配上有一套隐含的机制:记录着每次申请的大小以及起始地址,以便于释放时的查询?
...全文
139 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
cwanter 2002-11-13
  • 打赏
  • 举报
回复
原创:isno(isno)

Windows的HEAP管理机制简述
同LINUX一样,Windows的HEAP区是程序动态分配一块内存区域。程序员一般调用C函数malloc/free或者C++的new/delete或者WIN32 API函数HeapAlloc/HeapFree来动态分配内存,这些函数最终都将调用ntdll.dll中的RtlAllocateHeap/RtlFreeHeap来进行实际的内存分配工作,所以我们只需要分析RtlAllocateHeap/RtlFreeHeap就行了。

对于一个进程来说可以有多个HEAP区,每一个HEAP的首地址以句柄来表示:hHeap,这也就是RtlAllocateHeap的第一个参数。每个HEAP区的整体结构如下:

+-------------------------------------------------------------------+
| HEAP总体管理结构区 | 双指针区 | 用户分配内存区 |
+-------------------------------------------------------------------+
^ ^
|_hHeap |_hHeap+0x178

heap总体管理结构区存放着一些用于HEAP总体管理的结构,这不是我们所关心的。双指针区存放着一些成对出现的指针,用于定位分配内存以及释放内存的位置,这可能是某种树结构,我还没完全搞清楚。用户分配内存区是用户动态分配内存时实际用到区域,也这是HEAP的主体。

当我们调用RtlAllocateHeap(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes)来分配内存时将进行以下操作:
对参数进行检查,如果dwBytes过大或小于0都按照出错处理,根据dwFlags来设置一些管理结构;
检查是否为DEBUG程序,对于DEBUG的程序与实际运行的程序每个内存块之间的结构是不同的,所以我们下面说到的都是以RELEASE版编译的实际运行的程序(不是在MSDEV中调试的程序);
根据要分配的内存的大小(dwBytes)决定不同的内存分配算法,我们只分析小于1024 bytes的情况;
从双指针区找到用户内存区的末尾位置,如果有足够的空间分配所需的内存,就在末尾+dwBytes+8的位置放置一对指针来指向双指针区的指向用户内存区末尾位置的地方;
在后面同时设置双指针区的指向用户内存区末尾位置的指针指向进行完分配之后的用户内存区末尾位置。这么说可能有点绕,不过这跟HEAP溢出没有太大的关系,所以我们就不细究了。

两块连续分配的内存块之间并不是紧挨着的,而是有8字节的管理结构,最末尾的一块内存后面还另外多了8字节的指针指向双指针区,就是上面提到过的。

假设有以下程序:
buf1 = HeapAlloc(hHeap, 0, 16);
buf2 = HeapAlloc(hHeap, 0, 16);
连续分配了两块16字节内存,实际在内存中(用户分配区)的情况是这样的:

第一次分配后:
+-----------------------------------------------+
| buf1 | 8 byte |4 byte|4 byte|
+-----------------------------------------------+
| 用户内存 | 管理结构 | 两个指针 |

第二次分配后:
+---------------------------------------------------------------------------------+
| buf1 | 8 byte | buf2 | 8 byte |4 byte|4 byte|
+---------------------------------------------------------------------------------+
| 用户内存 | 管理结构 | 用户内存 | 管理结构 | 两个指针 |

在第二次分配内存的时候会利用第一块内存管理结构后面那两个指针进行一些操作,其中会有一次写内存的操作:

77FCB397 mov [ecx], eax
77FCB399 mov [eax+4], ecx

这时的eax和ecx分别指向:
+-----------------------------------------------+
| buf1 | 8 byte |4 byte|4 byte|
+---------------------------------^------^------+
| 用户内存 | 管理结构 |_eax |_ecx |
boolean6199 2002-11-13
  • 打赏
  • 举报
回复
据以上描述,似乎这套机制实际是由操作系统实现的,那么c++自身是否带有相关的管理机制?
一闻 2002-11-13
  • 打赏
  • 举报
回复
高!太深了!
熊主任 2002-11-12
  • 打赏
  • 举报
回复
这里是一个PS2引擎的部分代码:
DynamicHeapFreeBlockHeader
{
DynamicHeapFreeblockHeader* prev;
DynamicHeapFreeblockHeader* next;
unsigned int size;
unsigned int reserved;//保证结构体16位对齐
};//用于记录空白内存块的结构体
DynamicHeapUsedBlockHeader
{
unsigned int size;
unsigned int heap_id;
};//用于记录用掉内存块的结构体
其它还涉及一些复杂的操作就不是在这里能说完的了!
boolean6199 2002-11-12
  • 打赏
  • 举报
回复
这个机制具体是怎样的?
熊主任 2002-11-12
  • 打赏
  • 举报
回复
是有隐含机制的,系统会留一个内存头,记录所需信息。一般来说,再一些特定平台上,系统提供的new和delete不能满足我们的要求,我们就必须重载全局的new和delete,这时候就要靠我们自己来控制内存的分配了。
呵呵,有种一切尽在掌握的感觉~~

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧