堆的调试实验
-
调试态堆管理策略和常态堆管理策略:前者只使用空表不用块表,不真实
-
使用调试器加载函数会触发前者
-
__asm int3 调试最真实的栈
-
未启用块表的堆区信息
-
堆区起始位置(假设为0x00520000)
-
起始位置开始依次是段表索引,虚表索引,空表使用标识和空表索引区
-
空表索引区的位置是偏移0x178处
-
一个堆刚刚初始化时堆块的状态:
- 只有一个空闲的大块(尾块)
- 位于堆偏移0x0688处(启用块表后这个位置将是快表)(忽略掉8字节块首)
- Freelist[0]指向尾块
- 处零号空表索引外其余均指向自己,其余的空闲链表中都没有空闲堆块
-
块首:8字节
-
调试实验中堆分配的细节
(1)堆块的大小包括了块首在内,即如果请求 32 字节,实际会分配的堆块为 40 字节:8
字节块首+32 字节块身。
(2)堆块的单位是 8 字节,不足 8 字节的部分按 8 字节分配。
(3)初始状态下,快表和空表都为空,不存在精确分配。请求将使用“次优块”进行分配。
这个“次优块”就是位于偏移 0x0688 处的尾块。
(4)由于次优分配的发生,分配函数会陆续从尾块中切走一些小块,并修改尾块块首中的
size 信息,最后把 freelist[0]指向新的尾块位置。(找零钱) -
块表的状态HeapCreat(0,0,0)
-
变化:
- 尾块不再是0x0688偏移处,通过0x0178Freelist[0]处可以看出
-
堆刚初始化时块表是空的
-
申请8,16,24字节的堆空间再释放后:
- 之前0x0688处
- 释放后:
- 之前0x0688处
-
空表和块表堆块区别
-
块首只存指向下一堆块的指针,不存在指向前一堆块的指针
-
块首中的标识位为 0x01,也就是这个堆块是 Busy 状态