Ptmalloc与Tcmalloc浅析

Ptmalloc

内存分配

  1. Ptmalloc有多个area,包括一个在堆上分配内存的主分配区和使用mmap分配内存的非主分配区,使用area分配内存、释放内存、合并相邻空闲chunk都需要加锁。Ptmalloc分配内存时尝试获取一个可以加上锁的area,如果获取不到并且area没有超过上限会创建一个新的area;当达到area上限且加锁失败会循环尝试加锁直到获取到一个area。
  2. 用户请求分配的内存Ptmalloc中使用chunk表示, 每个chunk至少需要8个字节额外的开销。 Ptmalloc 将相似大小的chunk 用双向链表链接起来, 这样的一个链表被称为一个 bin。Ptmalloc 一共 维护了128 个bin,并使用一个数组来存储这些 bin。
  3. Ptmalloc会将分配的内存大小按16字节向上对齐,在内存池中找到相似大小的chunk并直接使用,如果找不到则找更大的chunk,然后拆为两部分,一部分分配给用户,一部分重新链接到合适的chunk下。
  4. 如果内存池中获取失败则会向系统申请。

内存优化总结:ptmalloc、tcmalloc和jemalloc

内存释放

  1. Ptmalloc中,所有调用delete释放的内存,并不是立即调用brk(sbrk)归还给操作系统,而是先将这个内存块挂在free-list里面进行内存归并(相邻的可用内存块合并为更大的可用内存块)。如果还与top chunk相邻则会合并到top chunk,当top chunk的大小达到malloc_trim的threshhold就会则调用malloc_trim归还部分可用内存给操作系统。
  2. glibc中设置了默认进行malloc_trim的threshhold为128K,也就是说当ptmalloc管理的free-list顶部最大连续可用内存>128K时,就会执行malloc_trim操作,归还部分内存给操作系统;而在可用内存<=128K时,即使程序中delete了这部分内存,这些内存也是不会归还给操作系统的。对外表现为调用delete之后,进程占用的内存并没有减少。
  3. 可调用malloc_trim(0)主动释放内存,它有两个作用:将threshhold设为0,释放free-list最顶层的内存;解除内存空洞中虚拟地址到物理地址的映射,把空洞的物理内存返回给系统,
  4. 调用mmap申请的内存会直接释放。

Ptmalloc的缺陷

  1. 后分配的内存先释放, ptmalloc 收缩内存是从free-list的 top chunk 开始,如果与 top chunk 相邻的 chunk不能释放, top chunk 以下的 chunk 都无法释放造成大量内存空洞。默认情况下top chunk的连续空闲内存大于128K时才会主动释放归还给操作系统。
  2. 多线程分配和释放内存以及合并空闲chunk时,需要对分配区area加锁造成比较大的开销。
  3. 内存从areana中分配, 不能从一个arena移动到另一个arena。如果多线程使用内存不均衡容易导致内存的浪费。 比如线程1使用了300M内存,完成任务后glibc没有释放给操作系统,线程2开始创建了一个新的arena,但是线程1的300M却不能用了。
  4. 用户请求分配的内存在ptmalloc中使用chunk表示, 每个chunk至少需要8个字节额外的开销。

【春节红包系列】一次"内存泄漏"引发的血案

Tcmalloc

TCMalloc解密
TCMalloc : Thread-Caching Malloc

相关概念

Size Class
Tcmalloc按大小分配了88个Size Class,每个Size Class都代表了一个大小,比如8B,16B,32B…256KB,16个字节以下间隔8字节。程序申请内存时会向上取整到Size Class的大小,比如7B申请8B的空间,15B申请16B的空间。
Span
Tcmalloc将虚拟内存分割成若干个8KB大小的page,连续n个page称为1个span。

ThreadCache
在这里插入图片描述
Tcmalloc为每个线程分配了一份单独的ThreadCache,每个ThreadCache对于每种Size Class都维持了一个链表,缓存了若干该Size Class大小的空闲对象。因为是thread local,所以从ThreadCache分配内存和释放内存不需要加锁,速度比较快。

CentralCache
在这里插入图片描述
ThreaCache的空间是从CentralCache申请来的,CentralCache是多个线程共享的一个缓存。它也为每种Size Class维持了一个链表,供各个线程的ThreadCache从此处申请和归还内存。因为需要加锁,所以ThreadCache每次会申请或者回收多个空闲空间。
PageHeap
在这里插入图片描述
CentralCache的空闲空间是从PageHeap申请的。PageHeap根据span的大小采取了2种不同的缓存策略,128page内的span,每个大小都用一个链表来缓存。超过128page大小的span存储在set中。

小对象分配

0-256KB的对象称为小对象,分配小内存对象主要有以下几步:

  1. 向上对齐到对应Size Class大小并遍历该Size Class大小的,然后遍历该链表找到第一个对象,将其从链表删除并返回;
  2. 如果ThreadCache对应的链表为空,则向CentralCache一次性申请若干个Size Class大小的空闲对象放到自己的链表上,重复1操作;
  3. 如果CentralCache也没有空闲空间,则向PageHeap申请1个best fit的span并拆分成若干个Size Class大小的对象放到CentralCache对应的链表上,CentralCache再把这些对象中的一部分放回到ThreadCache的链表上,重复1操作

中对象分配

256KB-1M的对象称为中对象,分配中对象主要有以下几步:

  1. 向上对齐到k个page,从k个page的span链表到128个page的span链表为止,找到第一个非空的span链表(n个page),取出第一个span拆为两部分:第一部分为k个page的span直接返回;剩下的n-k个page插入到n-k个page的span链表中;
  2. 如果128个page的span链表页无法满足要求,则视为大对象分配

大对象分配

大于1M的对象视为大对象,分配大对象主要有以下几步:

  1. 向上对齐到k个page,从存储span的set中找到best fit的span,拆分为两部分:第一部分为k个page的span直接返回;剩下的n-k个page组成的span如果大于128page,则插入到set中,否则插入到n-k个page的span链表中
  2. 如果set中也找不到合适的span,则调用brk或mmap向系统申请新的内存生成新的span,重新执行对应的对象分配算法

综上,三种对象的内存分配可以通过下图直观理解,不超过256KB的小对象分配,在应用程序和内存之间其实有三层缓存:PageHeap、CentralCache、ThreadCache。而中对象和大对象分配,则只有PageHeap一层缓存。
在这里插入图片描述

内存释放

当一个对象被回收时,Tcmalloc会计算它的大小。

  1. 小对象会被插入对应ThreadCache的SizeClass链表中;如果ThreadCache超过了预定大小,会将ThreadCache中的一部分空闲对象移到CentralCache对应SizeClass的链表中;当满足一定条件时,CentralCache中的空闲对象也会还给PageHeap,PageHeap再还给系统。

  2. 非小对象则直接放入PageHeap中best fit的链表或者set中。

Tcmalloc的优点

  1. ThreadCache会阶段性的回收内存到CentralCache里。 解决了ptmalloc2中arena之间不能迁移的问题。
  2. Tcmalloc占用更少的额外空间。例如,分配N个8字节对象可能要使用大约8N *1.01字节的空间。即多用百分之一的空间。Ptmalloc2使用最少8字节描述一个chunk。
  3. 更快, 256KB以下的小对象内存无锁分配。
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
本文通过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、付费专栏及课程。

余额充值