目录

TCmalloc简介

TCMalloc内部结构

TCMalloc 的工作模式

tcmalloc申请内存流程

tcmalloc释放内存流程


TCmalloc简介

TCMalloc 是 Google 自定义的 c 的 malloc () 和 c + + 操作符 new 的实现,用于 c 和 c + + 代码中的内存分配。TCMalloc 将 c 的 malloc () 和 c + + 操作符 new 的内部实现替换为 TCMalloc 的实现,开发者只需编译链接 TCMalloc 的静态库或动态库即可,无需改动任何与内存分配有关的代码。

TCMalloc 通常被用于提高内存分配的性能,实现了高效的内存管理。在与glibc中的内存分配器ptmalloc2作比较:

  • tcmalloc分配一次内存的时间更快
  • tcmalloc优化了对小对象的存储,需要更少的空间
  • tcmalloc特别在多线程方面做了优化,一方面是对于小对象(<32k)的分配基本不存在锁,内存资源竞争,另一方面是对大对象(>=32k)使用了细粒度、高效的自旋锁。
  • tcmalloc分配给本地线程的内存资源,在长时间空闲的情况下会被回收,供其他线程使用,提高了多线程时内存利用率,不会浪费内存,这一点ptmalloc2无法做到。

粒度解释:“粒度”表示的是精确程度问题。粗粒度角度描述一个系统,是关注系统中大的组件;细粒度角度描述一个系统是从组成大组件的小组件,或者更小组件的角度认识系统。
“粒度”此处是用来描述一个系统,或者对比多个系统的术语,它是一个相对的概念。

说明:glibc是GNU发布的libc库,即c运行库。glibc是linux系统中最底层的api,几乎其它任何运行库都会依赖于glibc。glibc除了封装linux操作系统所提供的系统服务外,它本身也提供了许多其它一些必要功能服务的实现。由于 glibc 囊括了几乎所有的 UNIX通行的标准,可以想见其内容包罗万象。而就像其他的 UNIX 系统一样,其内含的档案群分散于系统的树状目录结构中,像一个支架一般撑起整个操作系统。在 GNU/Linux 系统中,其C函式库发展史点出了GNU/Linux 演进的几个重要里程碑,用 glibc 作为系统的C函式库,是GNU/Linux演进的一个重要里程碑。(参考于glibc 简介: - the_tops - 博客园 (cnblogs.com))


TCMalloc内部结构

  • front-end :front-end 是一个缓存,它为应用程序提供内存的快速分配和释放。
  • middle-end :middle-end 负责为 front-end 填充或回收缓存。
  • back-end : back-end 负责从 OS 获取或释放内存。

TCMalloc 的工作模式

  1. tcmalloc会为每个线程分配本地缓存,小对象请求可以直接从本地缓存获取,如果没有空闲内存,则从central heap中一次性获取一连串小对象。
  2. tcmalloc对于小内存,按8的整数次倍分配,对于大内存,按4K的整数次倍分配。
  3. 当某个线程缓存中所有对象的总大小超过2MB的时候,会进行垃圾收集。垃圾收集阈值会自动根据线程数量的增加而减少,这样就不会因为程序有大量线程而过度浪费内存。

图1: Page和Span的关系

图2:通过PageMap实现Page到Span的映射\通过伙伴系统,实现了Span的分裂与合并

图3:每种规则的对象,都有一个CentralCache、向PageHeap申请Span,为用户分配对象

每种规则的对象都有一个独立的内存分配单元:CentralCache。在一个CentralCache内存,我们用链表把所有的Span组织起来,每次需要分配时就找一个Span从中分配一个Object;当没有空闲的Span时,就从PageHeap申请Span。

但是多线程情景,大家都在CentralCache分配资源,就会出现竞争。

每一个线程都有一个局部的 ThreadCache,如果ThreadCache不够了,就在CentralCache集中分配,如果CentralCache中依然没有内存可分配,就在PageHeap中申请Span,如果PageHeap没有合适的Page可以申请Span,就在操作系统中申请。

释放内存时,ThreadCache遵循着批量释放的原则,当对象积累到一定程度就释放上一层CentralCache;当CentralCache发现一个Span的内存完全释放了,就将这个Span归还给PageHeapPageHeap发现一批连续的Page都释放了,就归还给操作系统了。

tcmalloc申请内存流程

  1. 首先根据申请空间的大小从当前线程的可用内存块里面找(每个进程维护一组链表,每个链表代表一定大小的可用空间)
  2. .分配对象时,大的对象直接分配给Span,小的对象从Span中分配object
  3. . 如果没找到,就到central list里面查找(central list跟线程各自维护的list结构很像,为不同的size各自维护一组可用空间列表)
  4. 如果scentral list也没有找到,则计算分配size个字节需要分配多少page(变量:class_to_pages)
  5. 根据pagemap查找page对应的可用的span列表,如果找到了,则直接返回span,central list会将该span切割成合适的大小放入对应的列表中,然后交给thread cache
  6. 如果没有找到可用的span,则向OS直接申请,然后步骤同step 5。

page管理:

伙伴系统:合并相邻的page,减少外部碎片

内存申请:分裂Span

内存释放:合并Span

tcmalloc释放内存流程

1. 释放某个object

2. 找到该object所在的span

3. 如果该span中所有object都被释放,则释放该span到对应的可用列表,在释放的过程中,尝试将该span跟左右spans merge成更大的span

4. 如果当前thread cache的free 空间大于指定预置,归还部分空间给central list

5. central list也会试图通过释放可用span列表的最后几个span来将不用的空间归还给OS

tcmalloc向OS申请/释放资源是以span为单位的。

注意:tcmalloc向系统申请空间有三种方式:sbrk,mmap,/dev/mem文件,默认是三种都可以的,一种不行换另外一种。

注:大对象直接使用页级分配器(一个页是一个4K的对齐内存区域)从中央堆直接分配。

TCmalloc学习相关推荐

  1. 利用TCMalloc替换Nginx和Redis默认glibc库的malloc内存分配

    TCMalloc的全称为Thread-Caching Malloc,是谷歌开发的开源工具google-perftools中的一个成员.与标准的glibc库的Malloc相比,TCMalloc库在内存分 ...

  2. 计算机科学精彩帖子收集

    linux源码 LXR 源自"the Linux Cross Referencer",中间的"X"形象地代表了"Cross".与 Sourc ...

  3. redis 内存不足 排查_Redis 系统学习之 redis 内存模型

    关注:架构师学习路线,每日更新互联网最新技术文章与你不断前行,实战资料,笔试面试 前言 Redis是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说Redis是实现网站高并 ...

  4. Redis运维和开发学习笔记(6) 监控Redis工作状态-info命令

    Redis运维和开发学习笔记(6) 监控Redis工作状态-info命令 文章目录 Redis运维和开发学习笔记(6) 监控Redis工作状态-info命令 info server info clie ...

  5. 深入学习Redis(1):Redis内存模型

    前言 Redis是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说Redis是实现网站高并发不可或缺的一部分. 我们使用Redis时,会接触Redis的5种对象类型(字符串 ...

  6. 图解tcmalloc内存分配器

    目录 前言 如何分配定长记录? 如何分配变长记录? 大的对象如何分配? Span如何分配? 从Page到Span PageHeap 全局对象分配 ThreadCache 总结 参考 推荐阅读 前言 T ...

  7. go语言学习:语言简介

    一.Go语言简介 Go语言(或 Golang) 起源于 2007 年,并在 2009 年正式对外发布.Go 是非常年轻的一门语言,它的主要目标是"兼具 Python 等动态语言的开发速度和 ...

  8. TCmalloc (google开源项目核心部分模拟实现)

    目录 1什么是内存池 1.1池化技术 1.2内存池 2.开胃菜-设计一个定长内存池 代码实现: ObjectPool.h ObjectPool.cpp测试 3.TCmalloc(高并发内存池)整体框架 ...

  9. [go]深入学习Go总结

    Go 深入学习 文章目录 Go 深入学习 编译过程 概念 编译四阶段 词法分析 + 语法分析 类型检查 中间代码生成 机器码生成 类型系统 分类 底层类型 类型相同 类型赋值 类型强制转换 类型方法 ...

最新文章

  1. 信息系统项目管理知识--
  2. 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。...
  3. 新开通博客园,纪念一下。
  4. mysql 多数据库事务_多数据库事务处理
  5. linux下 添加一个新账户tom,linux 账户管理命令 useradd、groupadd使用方法
  6. 在el-table中使用el-popover,没法点击确定或取消来关闭添加 多个按钮
  7. Akka Remote Actor_简单示例二
  8. 在fc6上安装myeclipse全程记录
  9. Kerio Network Monitor
  10. 敏感词过滤算法DFA
  11. Dotween常用方法详解
  12. kubernetes(k8s)安装metrics-server实现资源使用情况监控
  13. python大数据工程师需要掌握哪些_大数据工程师 python
  14. 华为荣耀屏鸿蒙,荣耀智慧屏:华为鸿蒙迈出的第一步
  15. Arduino系列之米思齐旋钮控制LED灯亮度
  16. 安装程序时提示installshield wizard错误,错误代码-6003
  17. C语言基础——指针数组(指向数组的指针)
  18. Socialbook告诉你网红营销和ROI的关系~
  19. Webpack: Loader 开发分享
  20. xp 计算机没装网络控制器,windows xp系统没有无线网络,什么原因?

热门文章

  1. 18位身份证号码规则及js验证
  2. Linux(openSSL)上RSA密钥生成和使用(java)
  3. 浅谈情报的实践与落地
  4. 《西游》被测破15亿 笑点超泰囧
  5. 第十八天:WEB攻防-ASP安全MDB下载植入IIS短文件名写权限解析
  6. python编辑svg文件_使用Python批量转换SVG文件为PNG或PDF文件
  7. mysql 怎么设置ip地址_Mysql设置用户指定ip地址操作数据库的方法
  8. 软件定义边界(SDP)
  9. 惠普服务器dl380安装系统没有f10,惠普Hp DL380 GEN9 UEFI模式安装win2008 r2的方法
  10. org.fasterxml.classmate ResolvedParameterizedMember找不到