malloc/free
malloc的调用很快
一、VC6内存分配
heap想象为一堆内存
sbh_threshold 常量1016=1024-8(cookie) 为小区块服务SBH
代码执行次序是从下往上的
新版本VC10,无论分配内存的大小,都给heapAlloc(操作系统,其实为小区块shb的动作都放到操作系统中做的),不再给SHB
windows本身维护海量内存,你可以申请一块给你自己用
4096为初值,继续要的时候,4096会增长
BITVEC 32位的bit
bitvEntryHi+bitvEntryLo组合起来其实有64位 bit
内存分配的第一次
nSize=32*8=256 100h
下面为调试器分配的空间,100h以外的都是给debug用的:
调整大小,就是真正分出去的大小(sizeof(_CtrMemBlockHeader)+100h+4(无人区,防止写出去(黑客啥的))),就是下图右边的
头尾指针
memset :有些地方(无人区等等)会设初值,来检测变量是否改变
前面的大小就为size(256),1016=1024-8(cookie)
让扩充的大小和阈值比较,如果小,就让sbh服务,否则让操作系统(HeapAlloc)服务
调整后的大小:加上cookie,调整为16的倍数
131是130大小,1代表正在使用,还给shb时,置为130
两个指针,一个指向真正的内存,一个指向管理中心(16K):
有32个group,
每个group有64对指针,用作双向链表
需要构建一个region控制台,仍未开始实际分配内存
region结构如图:
struct tagEntry里面:
第一个表示指针借用前面的一部分而指向包括自己在内的三位【因为在后面控制8page时,需要设计成指向包括记录大小的头cookie和前后指针的三块内容;所以实际sizeFronnt=3,即从所指向的地址开始向下包括3块内容;另外因为设计成这样的功能,所以在GroupX中的64对某对链表指针没被投入使用时,一般都是往上指向前一个pEntryprev指针的地址从而向下包含3个的】。如下图所示。
第二个则表示类似链表的双向指针。
一个虚拟地址空间将被分32个小的虚拟地址空间,一个小的虚拟地址空间被分为8个page(4K)
上下设置-1(0xffffffff),未来合并内存的时候来区分不同的page
4080(4k=4096 - 黄色的,然后对16取整)是两个黄色之间的块
64个链表,分别负责 16 32 48 64 … 1024 的内存大小的分配 ,最后的1024的链表负责>=1k的
4080=ec0 真正要的是100h
MEM_RESERVE是让windows保留虚拟的空间地址,MEM_COMMIT是真正分配内存
32(个group)*64个bit,64个bit是来记录64个链表是否挂有内存,是的话,置位1
240h本来要找第35个的链表,但是bit【35】位0,退而求其次,找36(也为0),找到最后的64.
cntEntries:要分配就要+1,收回来-1,为0的时候就收回来了,可以换给操作系统了
回收的时候借用嵌入式指针(用自身的一部分作为指针),指向35号链表,将bit[35]=1
有下cookie才能向上合并,不然找不到上一个空闲区得边界
为什么要分为32group(一个group串很多个链表也行)?因为分为32段每段切小,那样回收内存还给OS的概率会变大
利用cntEntries判断时否全回收
cntEntries=0的时候,内存都还回来了,会是最开始的状态,因为散的内存最后都会被合并
不急着还给OS,因为下一次可能又向操作系统要,要有2个全回收再执行还
defer延缓,手上永远保留一个全回收或者null
归还所有的内存,会恢复最开始的状态
调试下,追踪链表的函数
GCC下的malloc也是这个行为,和上面讲的VC的malloc是一致的
malloc很快,其实一直调用malloc也没问题,allocator相比于malloc减小cookie,而不是提升速度。
allocator比较霸道,还的内存会一直拿到手上