目录
1.内存管理与堆
堆是程序虚拟内存中由低地址向高地址增长的线性区域。堆的位置一般在BSS段的高地址处。
一般堆管理机制由用户显式调用malloc()函数申请内存,调用free()函数释放内存。
(1)brk()和sbrk()
堆的属性是可读可写的,大小使用brk() 和sbrk()函数进行控制;通过调用brk()和sbrk()来移动program_break使得堆增长。在堆未初始化的时候,program_break指向BSS段的末尾。在堆初始化的时候,是否开启ASLR对堆的起始地址有影响,如果开启的话,则堆的起始地址start_brk会在BSS段之后的随机位移处;如果不开启,则在BSS段的末尾位置。brk()和sbrk()的具体实现方式见P225。
(2)mmap()和unmmap()
系统中的堆指的是主线程main_arena所管理的区域,每个线程都有属于自己的内存(arena).
用户正在使用中的堆块叫allocated chunk
被释放的堆块叫作free chunk,由free chunk组成的链表叫作bin
为了方便管理glibc将大小不同的chunk组成了不同的bin,如fast bin、small bin、large bin等,其中的chunk分别叫做fast chunk 、small chunk 和large bin。
chunk(高地址) | 下一个chunk |
chunk | |
chunk(低地址) | 上一个chunk |
2.重要概念和结构体
(1)arena
arena包含一片或数片连续的内存,堆块将会从这片区域划分给用户。主线程的arena(main_arena),它包含start_brk和brk之间的这片内存。
(2)heap_info
子线程的arena可以有多片连续内存,这些内存被称为heap,每一个heap都有自己的heap header(通过链表相连)
(3)malloc_state和malloc_chunk
每个线程只有一个arena header,里面保存了bins、top chunk 等信息。主线程的mian_arena保存在libc.so的数据段里,其他线程的arena则保存在给该arena分配的heap里面。
整个堆在初始化后会被当成一整个free chunk,称为top chunk ,当用户请求内存时,如果bins中没有合适的,就会从top chunk 中划分。用户释放内存时,glibc会先根据情况将释放的chunk与其他相邻的free chunk 合并,然后加入合适的bin中。
malloc_chunk结构体(构造及其结构内容):
INTERNALL_SIZE_T 的大小在64位系统下是6字节,32位系统下是4字节
prev_size:如果上一个chunk是释放状态(free chunk),prev_size用于表示其大小;否则作为上一个chunk的一部分,用于保存上一个chunk 的数据。
size:表示当前chunk的大小,必须是2*(SIZE_SZ)的整数倍(SIZE_SZ=8字节/4字节),最后3个比特位被用作状态标识,其中最低的两个比特位,从高到低分别是:
IS_MAPPED:用于标识一个chunk是否是从mmap()函数中获得的。如果用户申请内存过大,malloc会通过mmap()函数分配一个映射段。
PREV_INUSE:当它为1时,表示上一个chunk处于使用状态,否则表示上一个chunk是free chunk。
fd和bk:仅在当前chunk是free chunk时有效。chunk如果被释放会加入相应的bin中,fd指向下一个free chunk,bk指向上一个free chunk。如果是使用中的chunk ,则没有fd和bk。
fd_nextsize和bk_nextsiaze:与fd和bk相似,不同的是,他们仅用于large bin,分别指向前后第一个和当前chunk大小不同的chunk。
使用中的chunk:
free chunk: