堆chunk介绍

堆概述

  • 是虚拟地址空间的一块连续的线性区域

  • 提供动态分配的内存,允许程序申请大小未知的内存

  • 在用户.与操作系统之间,作为动态内存管理的中间人

  • 响应用户的申请内存请求,向操作系统申请内存,然后将其返回给用户程序

  • 管理用户所释放的内存,适时归还给操作系统

堆(chunk)内存是一种允许程序在运行过程中动态分配和使用的内存区域。相比于栈内存和全局内 存,堆内存没有固定的生命周期和固定的内存区域,程序可以动态地申请和释放不同大小的内存。被分配后,如果没有进行明确的释放操作,该堆内存区域都是一直有效的。

各种堆管理器

  • dlmalloc - General purpose allocator

  • ptmalloc2 - glibc

  • jemalloc - FreeBSD and Firefox

  • tcmalloc - Google libumem - Solaris

堆管理器并非由操作系统实现,而是由libc.so.6链接库实现。封装了-一些系统调用,为用户提供方便的动态内存分配接口的同时,力求高效地管理由系统调用申请来的内存。

arena

内存分配区,可以理解为堆管理器所持有的内存池 操作系统-->堆管理器-->用户 物理内存--> arena --> 可用内存 堆管理器与用户的内存交易发生于arena中,可以理解为堆管理器向操作系统批发来的有冗余的内存库存

chunk

用户申请内存的单位,也是堆管理器管理内存的基本单位 malloc()返回的指针指向一个chunk的数据区域

 

 

chunk的基本数据结构如下

struct malloc_chunk

{

INTERNAL_SIZE_T mchunk_prev_size; //size of previous chunk (if free)

INTERNAL_SIIZE_T mchunk_size; //size in bytes,including overhead

struct malloc_chunk* fd; //double links -- used only if free

struct malloc_chunk* bk; /* only used for large blocks:pointer to next larger size; */

struct malloc_chunk* fd_nextsize; //double links -- used only if free

struct malloc_chunk* bk_nextsize;

}

其中,mchunk size记录了当前chunk的大小,chunk的大小都是8字节对齐,所以mchunk_ size的 低3位固定为0 (8D= 1000B)。为了充分利用内存空间,mchunk_ size的低3位分别存储PREV_ INUS、IS_MMAPPED、NON_MAIN_ARENA信息。NON_MAIN_ARENA用来记录当前chunk是否不属于主线程,1表示不属于,0表示属于。IS_ MAPPED用来记录当前chunk是否是由mmap分配的。 PRE_INUSE用来记录前个chunk块是否被分配, 如果与当前chunk向 上相邻的chunk为被释放的状 态,则PREV_ INUSE标志位为0,并且mchunk prev_ size的大小为该被释放的相邻chunk的大小。堆 管理器可以通过这些信息找到前一个被释放chunk的位置。 chunk在管理器中有3种形式,分别为allocated chunk. free chunk和top chunk。当用户申请一 块内存后,堆管理器会返回一个allocated chunk,其结构为mchunk_ prev_ size+ mchunk size+ memory. user memory为可被用户使用的内存空间。free chunk为allocated chunk被释放后 的存在形式。top chunk是一个非常大的free chunk,如果用户申请内存大小比top chunk小,则由 chunk分割产生。在64位系统中,chunk结构最小为32 (0x20) 字节。

chunk的分类

按状态

  • malloced

  • free

按大小

  • fast

  • small

  • large

  • tcache

按特定功能

  • top chunk

  • last remainder chunk

堆的大小对齐 看一下堆的大小(size):| 堆的大小必须是2SIZE SZ的整数倍,如果申请的内存大小不是2SIZE_ SZ的整数倍,会被转成满足大小的最小的2*SIZE_ SZ的倍数; 32位系统中,SIZE_ SZ=4, 64位系统中SIZE_ SE=8;也就是32位系统堆大小为8的倍数,64位系统堆大小为16的位数,8对应的2进制为1000, 所以不管size如何变换对应的低3位固定为0; 为了不浪费这3个比特位,它们从高到低分别被用来示:

NON_ MIAN_ ARENA,记录当前chunk是否不属于主线程,1表示不属于,0表示属于。 IS_MAPPED,记录当前chunk是否是由mmap分配的。 PREV_INUSE,记录前一个chunk块是否被分配。

bin

管理arena中空闲chunk的结构,以数组的形式存在,数组元素为相应大小的chunk链表的链表头,存在于arena的malloc state中

  • unsorted bin

  • fast bins

  • small bins

  • large bins

  • (tcache)glibc-2.27

fast bin

Fast Bin分类的chunk的大小为32~128(0x80) 字节,如果chunk在被释放时发现其大小满足这个要求,则将该chunk放入Fast Bin,且在被释放后不修改下一个chunk的PREV INUSE标志位。Fast Bin 在堆管理器中以单链表的形式存储,不同大小的Fast Bin存储在对应大小的单链表结构中,其单链 表的存取机制是LIFO (后进先出)。一个最新被加入Fast Bin的chunk,其fd指针指向上一次加入Fast Bin的chunk。

unsorted bin

Unsorted Bin相当于Ptmalloc2堆管理器的垃圾桶。chunk被释放后, 会先加入Unsorted Bin中,等待下次分配使用。在堆管理器的Unsroted Bin不为空时,用户申请非Fast Bin大小的内存会先从 Unsorted Bin中查找,如果找到符合该申请大小要求的chunk (等于或者大于) ,则直接分配或者分割该chunk。

small bin

Small Bin保存大小为32 ~ 1024 (0x400) 字节的chunk, 每个放入其中的chunk为双链表结构,不同大小的chunk存储在对应的链接中。由于是双链表结构,所以其速度比Fast Bin慢- -些。 链表的存 取方式为FIFO (先进先出)。

large bin

大于1024 (0x400) 字节的的chunk使用Large Bin进行管理。Large Bin的结构相对于其他Bin是最 复杂的,速度也是最慢的,相同大小的L arge Bin使用fd和bk指针连接,不同大小的L arge Bin通过fd_nextsize和bk_nextsize按大小排序连接。



posted @ 2022-03-07 21:48  vi0let  阅读(1106)  评论(0编辑  收藏  举报