本文详细解析了进程堆的概念,包括其在系统中的作用、默认堆的特性、如何通过链接器改变大小,以及创建额外堆的目的。探讨了不同堆在内存管理、线程同步和快速释放方面的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在系统内部,堆就是一块预定的地址空间区域。 刚开始,区域内的大部分页面都没有调拨物理存储器。随着我们不断地从堆中分配内存,堆管理器会给堆调拨越来越多的物理存储器。这些物理存储器始终是从页交换文件中分配的。释放堆中的内存块时,堆管理器会撤销已调拨的物理存储器。

进程的默认堆

进程初始化的时候,系统会在进程的地址空间中创建一个堆。这个堆被称为进程的默认堆。

在默认情况下,进程默认堆的地址空间区域的大小是1M。

  • 改变其大小可以用/HEAP链接器。(仅适用于exe。dll没有与之关联的堆,因此在创建DLL的时不应该适用该链接器)

  • 关于/HEAP链接器详见:https://docs.microsoft.com/zh-cn/previous-versions/f90ybzkh(v=vs.120)

  • 对默认堆的访问必须依次进行。(系统保证不管在什么时候,一次只让一个线程从默认堆中申请或释放内存块)

  • 一个进程同时可以有多个堆,进程在整个生命周期内可以创建和销毁这些堆。

  • 默认堆是在程序运行之前由系统自动创建的,在程序终止后会自动销毁。我们无法销毁进程的默认堆。

  • 每个堆都有一个用来标识自己的堆句柄,所有分配和释放内存块的对函数都会在参数中用到这个堆句柄。

GetProcessHeap

可以通过GetProcessHeap来得到进程的默认堆句柄。

HANDLE GetProcessHeap();

创建其他的堆

为什么要在进程的地址空间中创建其他的堆(除默认堆)?

  • 对组件进行保护 --> 两个独立的堆互不影响
  • 更有效的内存管理 --> 如果每个堆只包含同样大小的对象,那么释放一个对象可以保证释放出的空间可以容纳另一个对象
  • 局部访问 --> 把内存访问局限在一个较小的地址区间内,将会降低系统需要在内存和磁盘之间进行交换的可能性。
  • 避免线程同步的开销 --> 同一时刻有多个线程要访问堆,堆函数必须执行额外的代码来保证堆的线程安全性。如果从堆中进行大量的分配操作,那么额外代码执行过多,会对程序的性能产生影响。创建一个新的堆,使只有一个线程可以访问对,就不必执行额外的代码了,但与此同时,我们自己就要保证堆的线程安全
  • 快速释放 --> 把一些数据结构存在一个专门的堆中,我们可以直接释放整个堆,而不用显式地释放每个内存块。

HeapCreate创建自己的进程中额外的堆

HANDLE HeapCreate(
  DWORD  flOptions,
  SIZE_T dwInitialSize,
  SIZE_T dwMaximumSize
);

HeapAlloc 从堆中分配内存块

LPVOID HeapAlloc(
  HANDLE hHeap,
  DWORD dwFlags,
  DWORD dwBytes
);

HeapReAlloc 调整内存块的大小

LPVOID  HeapReAlloc(
  HANDLE hHeap,
  DWORD dwFlags,
  LPVOID lpMem,
  DWORD dwBytes
);

HeapSize 获得内存块的大小

SIZE_T HeapSize(
  HANDLE  hHeap,
  DWORD   dwFlags,
  LPCVOID lpMem
);

HeapDestroy 销毁堆

BOOL HeapDestroy(
  HANDLE hHeap
);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值