tcmalloc

概述

下面的框图展示了tcmalloc的大致内部结构:

架构设计

我们可以将 tcmalloc 分为三个部分: front-end(前端)、middle-end(中端)、back-end(后端).

它们之间职责的可以粗略分为:

分配 (allocation)

前端可以处理特定大小的内存分配请求. 前端有一个内存缓存可用于分配或保存空闲内存, 该缓存由单独的线程访问. 所以它不需要任何锁, 并且大多数分配和释放速度都很快.

如果为前端设置合适的缓存大小, 理论上它可以满足任何请求. 如果特定大小的缓存耗尽, 前端会向中端请求一批内存来重新填充缓存.

如果中端缓存耗尽或者申请分配大小大于前端缓存处理的最大值, 则将请求转移到后端以满足大内存块分配, 或者重新填充前端缓存中的缓存.

释放 (Deallocation)

当一个(内存)对象被释放时:

中央空闲列表(central free list)

中央空闲列表(central free list)都被组织为两级数据结构:名为span的集合与每个span内的空闲对象链表.

从某个span的链表中删除第一个条目,来达到从中央空闲列表中分配对象的目的.(如果所有span都是空链表,则首先从中央页堆中分配一个适当大小的span.)

通过将对象添加到其包含范围的链表来实现归还到中央空闲列表, 如果链表长度等于span中小对象的总数,则该span现在完全空闲并将其返回到页堆.

调整合适线程缓存大小

正确调整线程缓存的free list大小是非常重要的! 因为当free list太小时,会频繁的将分配请求转移到 central free list. 而如果free list太大,则free list中的对象会被闲置导致内存浪费.

为了适当地调整free list的大小,我们使用慢启动算法以确定每个单独free list的最大长度. free list的使用频率越高,其最大长度也会随之增加. 如果某个free list更多地用于释放而不是分配,则它的最大长度只会增长到可以立即移动到central free list的程度.