进一步理解C++中的堆(Heap)

最近的项目涉及到Heap Corruption的问题,所以对堆要有更深的理解。

进程初始化时会被分配一个默认大小为1M的默认堆,这个堆会被很多重要的函数调用,比如当我们调用ANSI版本的某些函数时,它们的Unicode版本字符串就会存于其中。若应用程序中有多个线程都用到了默认堆,那么会有机制使得同时只能有一线程能在默认堆中进行操作。默认堆的分配和销毁都是由系统控制的,但是我们可以通过GetPreocessHeap()来得到本进程的默认堆句柄。

常用的分配函数有VirtualAlloc和HeapAlloc.VirtualAlloc请求4K为边界的整块虚拟内存,HeapAlloc分配任意大小的内存块。但后者是依赖前者实现的。也就是说在操作系统的层面上管理内存的最小单位是4K。要实现更小的内存管理(即HeapAlloc),需要用户态的程序自己去分配,比如说Windows的HeapManager。在分配时先用分配足够大的4K倍数的空间,再去进行内部的分配和回收。一般而言,对于小于1M的地址空间,我们一般使用HeapCreate(),但是更大的话,会倾向于用VirtualAlloc()在虚拟内存中分配。

以Alloc结尾的函数都只是分配堆空间,而真正的要去创建一个堆,要使用HeapCreate()。HeapCreate()会返回一个新堆的句柄,而各种alloc函数可以利用这个句柄在不同的堆空间上进行内存分配。在不同的堆上进行alloc可以有效的避免内存碎片的问题,因为当某一个堆中的内容不再需要时,我们可以将这个堆整个的HeapDestroy()掉。但是,若各种数据都存于一个堆中,则要Destroy整个堆必须保证所有的数据都不再需要。

当我们先把一个地址空间HeapFree之后,若HeapManager没有进行VirtualFree的操作,再次访问该地址操作系统并不会报错。因为以HeapFree和HeapAlloc都是由HeapManager来控制的,而操作系统一般情况下的界定粒度为4k。如果只是在HeapManager的控制范围内发生了越界,操作系统可能并不会认为这有什么错误。(因为没有在以4k为粒度的内存上越界)。

在各种create中,经常会有HEAP_NOSERIALIZE这个标志,它的作用是对堆进行线程访问控制。若这个标志被加到参数中,那么同一时刻,可以有多个线程对同一个堆进行堆操作。反之亦然。如果我们不用这个参数,还有两个可用函数HeapLock()和HeapUnlock()达到类似效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微个日光日

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值