glibc内存管理模块ptmalloc架构透析

之前写了一篇关于ptmalloc的malloc/free代码解析的博客,有同事看到说,在不熟悉ptmalloc架构的情况,即使注释写的再详细,也不是很好理解,建议再写一些架构介绍的博文,年前后这段时间一直在忙其他事情,打算最近抽出一些时间完成这个任务。

ptmalloc的设计遵循以下原则:

1,较大块的内存,占用周期长得内存使用mmap分配,使用时间短的内存使用brk,如果不了解brk和mmap这两个系统调用,请看这里

2,缓存小的,临时使用的内存,大块内存和长时间使用的内存直接跟kernel交互。

3,malloc和free在必要的时候会合并或者切割以保证能拿到合适的内存块。

4,分配区最大粒度的单位为分配区(arena),可能有多个,包括一个主分配区(main arena)和不定数量的非主分配区(non main arena),非主分配区数目只增不减。

5,每个分配区都配有mutex,在操作分配区时需加锁,属于比较浪费性能的地方,最新的版本已经使用原子操作代替某些锁操作。

6,非主分配区只使用mmap跟OS索取内存,通过使用宏HEAP_MAX_SIZE,32位系统每次1M,64位为64M

宏声明如下:

# if __WORDSIZE == 32
#  define DEFAULT_MMAP_THRESHOLD_MAX (512 * 1024)
# else
#  define DEFAULT_MMAP_THRESHOLD_MAX (4 * 1024 * 1024 * sizeof(long))
# endif
#  define HEAP_MAX_SIZE (2 * DEFAULT_MMAP_THRESHOLD_MAX)


前面已经说了,内存的最大组织单位为分配区(arena),而内存分配的基本单位为trunk。

ptmalloc将一部分大小差不多(smallbin完全相等,largebin在一定范围)的chunk用双向链表连接起来,这样一个链表被叫做一个bin。

glibc一共维护128个bin,以数组的方式管理每个bin的头结点,是个很典型的hash结构。

1,除index为0外,所有数组是按chunk的大小递增排列的。

2,index为0的bin为unsorted bin,字面意思是没有排序的chunk,这个bin里面是刚刚释放的内存,没有整理到后面的有序chunk链表中。

3,index从1到64的bin被称为small bin,同一个bin中的chunk大小完全相同。

4,每两个相邻的smallbin的chunk大小相差8个bytes。

5,index从64到127的bin被称为largebin,同一个bin中的chunk大小在一个范围内,从头到位按从大到小排序(大的在头,便于查找所需的空间)。

6,为了提高小内存的申请和释放效率(事实上,通常大块内存申请释放的频率不是很高),所以对于应用程序释放的小于某个阀值的内存(默认64B)会被装入一个叫做fastbin的容器中,当应用程序再次申请不大于这个阀值的内存时,会首先从fastbin中找寻。glibc会周期性地遍历fastbin,将空闲chunk合并,归入unsortedbin然后装入bin中


除了双向链表和数组联合表示的bin类trunk结构之外,chunk还有其他的组织方式。

1,Top chunk

主从分配区的Top chunk是不一样的

从分配区通过mmap分配一块较大的子heap区域,因为内存从低到高分配,则高处空闲的一块chunk即为top chunk

主分配区用sbrk改更改break位置来修改进程heap区域,malloc第一次被调用时glibc会给分配一块(size + 128)大小的四字节对齐大小的内存,是为主分配区的top Chunk。

top chunk总是在fastbins和bins之后的第三选择。

2,mapped chunk

当需要的chunk非常大,bin和topchunk都不能满足需求时,glibc会直接使用mmap通过匿名映射得到大块内存,提供给应用程序。

这种chunk在free时会直接通过unmmap解除映射,将内存归还操作系统,所以大块内存操作对于glibc来说属于效率非常低的。

mapped chunk至始至终不会归于任何bin结构管理,free的内存再次操作会导致非法内存访问。

3,last remainder

last remainder同样不会属于bin管理。

如果需要一个比较小的内存,但是smarllbins中找不到合适的chunk,同时last remainder大于所需的内存大小,则从里面切割出来一部分给应用,另外的部分仍然作为last remainder




本文通过Glibc内存暴增问题,主要介绍了系统的内存管理问题,具体如下: 目录 1. 问题 2. 基础知识 2.1 X86平台Linux进程内存布局 2.1.1 32位模式下进程内存经典布局 2.1.2 32位模式下进程默认内存布局 2.1.3 64位模式下进程内存布局 2.2 操作系统内存分配的相关函数 2.2.1 Heap操作相关函数 2.2.2 Mmap映射区域操作相关函数 3. 概述 3.1 内存管理一般性描述 3.1.1 内存管理的方法 3.1.2 内存管理器的设计目标 3.1.3 常见C内存管理程序 3.2 Ptmalloc内存管理概述 3.2.1 简介 3.2.2 内存管理的设计假设 3.2.3 内存管理数据结构概述 3.2.4 内存分配概述 3.2.5 内存回收概述 3.2.6 配置选项概述 3.2.7 使用注意事项 4. 问题分析及解决 5. 源代码分析 5.1 边界标记法 5.2 分箱式内存管理 5.2.1 Small bins 5.2.2 Large bins 5.2.3 Unsorted bin 5.2.4 Fast bins 5.3 核心结构体分析 5.3.1 malloc_state 5.3.2 Malloc_par 5.3.3 分配区的初始化 5.4 配置选项 5.5 Ptmalloc的初始化 5.5.1 Ptmalloc未初始化时分配/释放内存 5.5.2 ptmalloc_init()函数 5.5.3 ptmalloc_lock_all(),ptmalloc_unlock_all(),ptmalloc_unlock_all2() 5.6 多分配区支持 5.6.1 Heap_info 5.6.2 获取分配区 5.6.3 Arena_get2() 5.6.4 _int_new_arena() 5.6.5 New_heap() 5.6.6 get_free_list()和reused_arena() 5.6.7 grow_heap(),shrink_heap(),delete_heap(),heap_trim() 5.7 内存分配malloc 5.7.1 public_mALLOc() 5.7.2 _int_malloc() 5.8 内存释放free 5.8.1 Public_fREe() 5.8.2 _int_free() 5.8.3 sYSTRIm()和munmap_chunk(
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值