0x00 堆的工作原理
0x0 数据结构
堆块
堆块包括块首与块身(返回的指针指向),块首是一个堆块头部的几个字节,用来标识这个堆块自身的信息。
未被占用的堆区
被占用的堆区
堆表
位于堆区的起始位置,堆表分为两种空闲双向链表Freelist(空表 128条)和快速单向链表Lookaside(快表 最多只有四项)
堆区一开始的堆表区中有一个128项的指针数组(看到有人说把它看成队列的),被称作空表索引。该数组的每一项包含两个指针,用于表示一条空表。
free[1] 标识了所有堆中所有大小为8字节的空闲堆块,之后每个索引指示的空闲堆块递增8个字节。即:
free[2]标识了16个字节的空闲堆块。
free[k] 标识了 k * 8 个字节的空闲堆块。
![]()
空闲双向链表Freelist(空表)
快速单向链表Lookaside(快表)
0x1 申请
堆块的分配有三类:
- 块表分配
- 普通表份分配
- 零号表分配(free[0])
堆的申请首先在快表中查询,如果没有去普通表中查询,如果还没有从内存空间分配。
0x2 使用
直接利用堆表中的指针查询堆块,利用返回的指针使用堆内存,并对其操作。
0x3 释放
堆的释放首先释放在快表中,如果快表满了再释放到普通表中。
空表 内存分布
0x00520178 Freelist[0]
0x00520188 Freelist[1]
0x00520198 Freelist[2]
0x005201a8 Freelist[3]
块区
0x00520680 h1 (加上8byte头字节)
0x00520690 h2
0x005206a0 h3
0x005206b0 h4
快表 内存分布
0x003606E8 Lookaside[1]
0x00360718 Lookaside[2]
0x00360748 Lookaside[3]
0x00360788 Lookaside[4]
堆区
0x00361E98 h1
0x00361Ea8 h3
0x00361E98 h5