关于Windows下堆内存的申请与释放

来源:畅享网  
2011/12/16 11:20:18
我们都知道,C语言中要动态申请内存需要调用malloc函数,释放动态内存需要调用free函数。内存的申请与释放都是在堆(Heap)上进行的。当然,所谓的内存,都是虚拟内存。

本文关键字: Windows 下堆内存 申请 释放
我们都知道,C语言中要动态申请内存需要调用malloc函数,释放动态内存需要调用free函数。内存的申请与释放都是在堆(Heap)上进行的。当然,所谓的内存,都是虚拟内存。
 
C语言中的malloc和free,在windows中主要是通过HeapAlloc和HeapFree来实现的。
 
每个进程在初始化的时候,会调用RtlProcessHeap()函数构造进程的HEAP对象,这个对象用来管理进程的堆内存。
 
当我们使用malloc申请一段内存时,我们要指定大小,但是使用free释放的时候,只是指定要释放的内存起始地址即可。
 
如:
 
int_*p = (int*)malloc(100_*sizeof(int)); // 申请100个int大小的一段内存
 
... // 其他操作
 
free(p); // 释放p所指向的内存
 
那么我们必定会产生疑问,系统是怎么知道或记录给定指针所指向的动态内存的大小的呢?
 
windows的实现方案很简单,就是在每一段动态内存的上部保存该段内存的大小等相关信息,这也就说明了,当我们使用堆内存时,会有额外的系统开销,windows中是通过如下一个结构体来保存相关信息的:
 
(WRK中的定义,在XP和win7下测试符合,win2000源码中的定义与此不同)
 
view plain
 
typedef struct _RTL_HEAP_ENTRY {
 
SIZE_T Size; // 指示该段内存的大小
 
USHORT Flags;
 
USHORT AllocatorBackTraceIndex;
 
union {
 
struct {
 
SIZE_T Settable;
 
ULONG Tag;
 
} s1; // All other heap entries
 
struct {
 
SIZE_T CommittedSize;
 
PVOID FirstBlock;
 
} s2; // RTL_SEGMENT
 
} u;
 
} RTL_HEAP_ENTRY, *PRTL_HEAP_ENTRY;
 
因为free释放内存的时候要依赖于该结构体中的信息,所以对于不是malloc返回的地址或已被释放过的地址,该结构的内容一般是不正确的,这也就是free会出错的原因。
 
如:
 
int_*p = (int*)malloc(100_*sizeof(int)); // 申请100个int大小的一段内存
 
... // 其他操作
 
free(p); // 释放p所指向的内存
 
free(p); // 再次释放已释放的内存,会出错,因为RTL_HEAP_ENTRY已经不再有效。
 
所以当我们释放指针所指的动态内存后,我们最好将指针赋值为NULL,因为free一个值为NULL的地址,不会有任何错误。
 
再如:
 
int_*p = (int*)malloc(100_*sizeof(int)); // 申请100个int大小的一段内存
 
... // 其他操作
 
//比如我们想释放部分内存
 
int_*q = p + 20;
 
free(q); // 释放q所指向的内存,会出错,因为地址q所对应的RTL_HEAP_ENTRY结构体信息是无效的
 
所以free只能释放malloc返回的有效地址。
 
下面通过一个程序验证一下:
 
view plain
 
#include
 
#include
 
typedef struct _RTL_HEAP_ENTRY {
 
SIZE_T Size;
 
USHORT Flags;
 
USHORT AllocatorBackTraceIndex;
 
union {
 
struct {
 
SIZE_T Settable;
 
ULONG Tag;
 
} s1;
 
struct {
 
SIZE_T CommittedSize;
 
PVOID FirstBlock;
 
} s2;
 
} u;
 
} RTL_HEAP_ENTRY, *PRTL_HEAP_ENTRY;
 
int main()
 
{
 
PRTL_HEAP_ENTRY pHeapEntry;
 
int *p;
 
for(int i = 0; i < 1000; i++)
 
{
 
p=(int*)malloc(i);
 
pHeapEntry=(PRTL_HEAP_ENTRY(p)-1);
 
printf("i: %d, size: %d\n", i, pHeapEntry->Size);
 
free(p);
 
}
 
return 0;
 
}
 
输出结果是:
 
i: 0, size: 0
 
i: 1, size: 1
 
i: 2, size: 2
 
...
 
i: 999, size: 999
 
总结:本文根据windows源码简单的分析了windows对C库函数free的实现中对内存大小信息的记录方法。
责编:何先辉
vsharing微信扫一扫实时了解行业动态
portalart微信扫一扫分享本文给好友

著作权声明:畅享网文章著作权分属畅享网、网友和合作伙伴,部分非原创文章作者信息可能有所缺失,如需补充或修改请与我们联系,工作人员会在1个工作日内配合处理。
最新专题
IT系统一体化时代来了

2009年Oracle 用Exadata服务器告诉企业,数据中心的IT服务一体化解决方案才是大势所趋,而当前企业对大数据处理的..

高性能计算——企业未来发展的必备..

“天河二号”问鼎最新全球超级计算机500强,更新的Linpack值让世界认识到了“中国速度”。但超算不能只停留于追求..

    畅享
    首页
    返回
    顶部
    ×
      信息化规划
      IT总包
      供应商选型
      IT监理
      开发维护外包
      评估维权
    客服电话
    400-698-9918