堆
在程序运行过程中,堆可以提供动态分配的内存,允许程序申请大小未知的内存。堆其实就是程序虚拟地址空间的一块连续的线性区域,它由低地址向高地址方向增长。我们一般称管理堆的那部分程序为堆管理器。
堆管理器处于用户程序与内核中间,主要做以下工作
1.响应用户的申请内存请求,向操作系统申请内存,然后将其返回给用户程序。同时,为了保持内存管理的高效性,内核一般都会预先分配很大的一块连续的内存,然后让堆管理器通过某种算法管理这块内存。只有当出现了堆空间不足的情况,堆管理器才会再次与操作系统进行交互。
⒉管理用户所释放的内存。一般来说,用户释放的内存并不是直接返还给操作系统的,而是由堆管理器进行管理。这些释放的内存可以来响应用户新申请的内存的请求。
Linux 中早期的堆分配与回收由Doug Lea实现,但它在并行处理多个线程时,会共享进程的堆内存空间。因此,为了安全性,一个线程使用堆时,会进行加锁。然而,与此同时,加锁会导致其它线程无法使用堆,降低了内存分配和回收的高效性。同时,如果在多线程使用时,没能正确控制,也可能影响内存分配和回收的正确性。Wolfram Gloger在Doug Lea的基础上进行改进使其可以支持多线程,这个堆分配器就是ptmalloc。在glibc-2.3.x.之后, glibc中集成了ptmalloc2。
堆相关的数据结构
堆的操作相当的复杂,那么在glibc内部必然也有精心设计的数据结构来管理它。与堆相应的数据结构主要分为宏观结构,包含堆的宏观信息,可以通过这些数据结构索引堆的基本信息。微观结构,用于具体处理堆的分配与回收中的内存块。
该结构体定义了有6个变量
微观结构 malloc chunk
fd指向下一个元素
bk执向前一个元素
一个chunk 在内存中的状态
这里 上一个chunk加上size 就能找到下一个chunk的位置
当该chunk被释放的时候
当一个chunk处于使用状态时,它的下一个chunk的prev_size域无效,所以下一个chunk的该部分也可以被当前chunk使用。这就是chunk中的空间复用。