Linux堆内存管理glibc

1. struct _heap_info, struct malloc_state和struct malloc_chunk

typedef struct _heap_info
{
  mstate ar_ptr;            /* Arena for this heap. */
  struct _heap_info *prev;  /* Previous heap. */
  size_t size;              /* Current size in bytes. */
  size_t mprotect_size;     /* Size in bytes that has been mprotected
                             PROT_READ|PROT_WRITE.  */
  /* Make sure the following data is properly aligned, particularly
     that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
     MALLOC_ALIGNMENT. */
  char pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK];
} heap_info;


struct malloc_state
{
  /* Serialize access.  */
  __libc_lock_define (, mutex);
 
  /* Flags (formerly in max_fast).  */
  int flags;
 
  /* Set if the fastbin chunks contain recently inserted free blocks.  */
  /* Note this is a bool but not all targets support atomics on booleans.  */
  int have_fastchunks;
 
  /* Fastbins */
  mfastbinptr fastbinsY[NFASTBINS];
 
  /* Base of the topmost chunk -- not otherwise kept in a bin */
  mchunkptr top;
 
  /* The remainder from the most recent split of a small request */
  mchunkptr last_remainder;
 
  /* Normal bins packed as described above */
  mchunkptr bins[NBINS * 2 - 2];
 
  /* Bitmap of bins */
  unsigned int binmap[BINMAPSIZE];
 
  /* Linked list */
  struct malloc_state *next;
 
  /* Linked list for free arenas.  Access to this field is serialized
     by free_list_lock in arena.c.  */
  struct malloc_state *next_free;
 
  /* Number of threads attached to this arena.  0 if the arena is on
     the free list.  Access to this field is serialized by
     free_list_lock in arena.c.  */
  INTERNAL_SIZE_T attached_threads;
 
  /* Memory allocated from the system in this arena.  */
  INTERNAL_SIZE_T system_mem;
  INTERNAL_SIZE_T max_system_mem;
};

struct malloc_chunk {
 
  INTERNAL_SIZE_T      mchunk_prev_size;//物理地址上相邻的前一个chunk的大小
  INTERNAL_SIZE_T      mchunk_size;//该chunk大小
 
  struct malloc_chunk* fd;//被分配时:用户数据的起始地址;未被分配时:指向前一个空闲chunk
  struct malloc_chunk* bk;//指向后一个空闲
 
  struct malloc_chunk* fd_nextsize; //指向前一个与本chunk大小不同的chunk
  struct malloc_chunk* bk_nextsize; //指向后一个大小不同chunk
 
};

关系: _heap_info -> malloc_state(arena) 管理malloc_chunk链表。_heap_info 对应一个堆段,和arena可能多对一。

当线程首次调用malloc时会先检查创建的arena有没有到上限,如果没有则创建,如果达到了则试图加锁一个现存的arena。

只有主arena才能调用brk在堆段上申请空间,而失败时才会调用mmap,分arena空间不足时只能通过mmap创建新heap(注意和linux内存空间上的heap是两个概念这里),通过mmap申请的空间在free时会直接munmap释放。

2. fastbins和bins

一个bin就是一个由malloc_chunk组成的链表,且都是未分配的chunk,这就是为什么其fd成员只有在未分配状态下才是一个指向chunk的指针。

fastbins

chunk size: 32 - 128 byte

链表数:10

中保存32-128 byte(包含结构体成员)的chunk,单链表,LIFO;注意,malloc_state中fastbinsY中保存的是多条fastbin链表。一种大小的一条,小size 的链表头在前,大的在后(类似STL的二级空间allocater)。

bins

unsorted bin

chunk size: 大于128,free后未被整理的chunk

链表数:1

small bin

chunk size:  2 * SIZE_SZ * index, 最大为2*4*63 = 504, 64位下为1008

链表数:62

large bin

chunk size: 分为6组,每组的每条链表代表一个区间,组与组之间区别在于不同的区间步长。最大无上限。

链表数:32 + 16 + 8 + 4 + 2 + 1 = 63

 

3. malloc(_int_malloc)的过程

bins的管理其实不涉及到内核操作,即没有系统调用,malloc优先查找的是bin中的chunk,若没有合适的chunk则会到堆顶的top_chunk(向内核申请的但没有使用也没有进入bin的空间),若top_chunk不够才会调用brk/mmap扩大top_chunk。而被free的chunk的指针会交由对应大小的bin保管。malloc不会主动将top_chunk的空间划分给bin,也就是说bin中的chunk都是从回收中来的。

执行顺序:

1. 寻找可用的arena

2. 判断大小是否符合fastbin,smallbin以及查找有无可用chunk;

3. 如果没返回,说明没找到或大小超过smallbin不符,执行malloc_consolidate(整合,合并fast_bins中相邻chunk,并将unsorted_bin中的chunk分到其他bin中),整理以当前arena为单位

具体实现看这篇https://blog.csdn.net/qq_41453285/article/details/97627411

4. 进入循环依次查找unsortedbin(包含整合),smallbin, largebin, topchunk,其中对前三者的搜索如果找不到相等的块则找比申请大小大的chunk进行切割; 最后判断top chunk,如果不够再调用sysmalloc扩大topchunk, 或直接mmap一个chunk给用户(若请求大于128K).

*可以看出整个过程只有最后的sysmalloc才经过内核,而topchunk以下的空间其实已经算是合法的用户地址空间了,这就是为什么没有malloc的一些空间也能访问而不产生运行时错误。

*last_remainder指向切割后的余下部分,当申请大小为smallbin时优先用它来切割,为了提高小内存的空间局部性。

4. 还给操作系统

1. 如果是mmap创建的chunk直接munmap。

2.heap则需要在free掉top chunk相邻的chunk、将chunk与top chunk合并时,若top chunk大于一个阈值则交还一部分给操作系统。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值