当前位置: 首页 > news >正文

jemalloc 5.3.0的tsd模块的源码分析

一、背景

在主流的内存库里,jemalloc作为android 5.0-android 10.0的默认分配器肯定占用了非常重要的一席之地。jemalloc的低版本和高版本之间的差异特别大,低版本的诸多网上整理的总结,无论是在概念上和还是在结构体命名上在新版本中很多都找不到,而高版本尤其5.x.x版本就几乎没有现成的网上整理文档。这篇博客作为jemalloc 5.3.0专栏里的第一篇,后续会不断更新jemalloc 5.3.0版本的源码分析及实验对比,揭开jemalloc 5.3.0里的诸多实现上的细节。

这篇博客,我们会先介绍jemalloc 5.3.0里的tsd模块,为什么第一篇jemalloc 5.3.0的博客要介绍这个tsd模块呢?因为在jemalloc 5.3.0里,tsd模块算是一个基础组件模块,不先分析tsd模块,绕开它,会让源码分析困难重重。另外,tsd模块在实现上有不少编程上的技巧,不少技巧对于我们C++尤其C的开发人员也是非常值得借鉴的,尤其tsd模块里的若干宏定义和展开的实现,极简的优化了代码量,这种C的宏展开方式来达到的最终代码执行的效果,虽然从代码阅读上可能会有些晦涩,但是一旦掌握以后,它所带来的代码简化收益会相当可观,实现上可能会比替代用C++的大量的抽象和继承而定义的大量的冗余的类而言,从长期阅读观感上会更为极简。

我们会在第二章里先介绍jemalloc 5.3.0里的tsd模块的实现细节,其底层用到的glibc的tls机制细节可以参考之前的博客 线程局部存储tls的原理和使用-CSDN博客,然后在第三章里,我们对第二章里介绍的一些细节进行提炼和抽象,抽象出可以进行复用的编程上的技巧,作为我们一线开发人员长期编码上的一些参考。

二、jemalloc 5.3.0里的tsd模块的实现细节

我们先在 2.1 里介绍一下jemalloc 5.3.0的代码下载编译,并介绍个人在为了方便调试和调试分析的编译方式和进行jemalloc库的调试。在 2.2 里我们介绍tsd模块的用途和实现原理。

2.1 jemalloc 5.3.0的代码下载、编译和调试

2.1.1 代码下载和编译

jemalloc的github网址:

https://github.com/jemalloc/jemalloc

下载命令:

git clone https://github.com/jemalloc/jemalloc.git

cd jemalloc以后,执行如下命令切换到 5.3.0 版本:

git checkout 5.3.0

2.1.2 为了方便调试分析修改了一下源码和编译参数

关于tsd模块有一个宏定义的名字过长导致变量的名字过长,造成在通过vs2019进行ssh的gdb调试时,显示不出完整的变量名,造成代码分析的障碍,所以,临时为了调试方便,把该宏改短:

在tsd.h里,原始的宏定义如下:

临时改成(下面的名字可按照个人情况随意指定):

改完以后,先要执行自动生成编译用的文件的指令:

./autogen.sh

如果遇到如下错误:

则需要进行autoconf的安装:

apt-get update
apt-get install autoconf

安装完autoconf以后,重新执行./autogen.sh

在make之前,配置一下参数,使用O0,覆盖掉原来的O3:

./configure CFLAGS="-O0"

然后再执行make

如果遇到如下warning:

可以忽略,或者修改一下configure.ac文件里的ARFLAGS,下图是原始的内容:

修改成:

重新执行一遍上面的./autogen.sh ./configure xxx make clean;make -jx的流程以后,就不会遇到“ar: `u' 修饰符被忽略,因为 `D' 为默认(参见 `U')”的错误了。意思就是有了‘D’作为默认,ARFLAGS的‘u’就会被忽略,那就是不需要这个‘u’,去掉即可。

2.1.3 调试jemalloc库

经过上面的编译之后,生成物默认在jemalloc文件夹下的lib目录下,把它们拷贝到/usr/lib下:

然后我们参考 linux上对于so库的调试——包含通过vs2019远程ssh调试so库_vs2019 gdb调试-CSDN博客 这篇博客的方法进行远程ssh进行gdb调试jemalloc的库(博客里举的例子就是调试jemalloc库的例子)。

2.2 tsd模块的用途和实现原理

2.2.1 tsd模块借助的是glibc提供的tls机制

jemalloc 5.3.0里的tsd的意思是指Thread-Specific-Data,用的是之前的博客 线程局部存储tls的原理和使用-CSDN博客 提到的glibc的tls机制来实现的。jemalloc有关tsd的注释:

2.2.2 tsd模块实际用到的就4个文件

tsd模块的源文件就一个是src/tsd.c,头文件有多个:

但是对于x86_64 linux平台,根据tsd.h里下面这段根据编译选项来决定用那个头文件,而不用另外的几个头文件:

上图中,根据增加#err来确定,x86_64 linux平台,用的就是tsd_tls.h头文件。所以tsd模块里我们需要关注的头文件就只有下面这三个:

tsd.h

tsd_tls.h

tsd_types.h

所以,tsd模块在x86_64 linux平台实际用到的就4个文件:

tsd.c tsd.h tsd_tls.h tsd_types.h

2.2.3 tsd模块实现的核心是tsd.h文件,struct tsd_s按照TSD_DATA_SLOW、TSD_DATA_FAST、TSD_DATA_SLOWER定义不同的场景下用到的数据

在tsd.h的一开头的注释里有如下内容:

注释里清晰地表达了为了提高cache命中率,把不同场景下可能会用到的数据各自放到临近的区域,虽然TSD_DATA_SLOW、TSD_DATA_FAST、TSD_DATA_SLOWER用到的数据都定义在strcut tsd_s这个结构体里:

但是它们不同的path(fast-path或slow-path)用到的数据从定义的位置上都是连续的。

在tsd模块里的若干关键函数,如tsd_fetch_slow、tsd_state_set、tsd_add_nominal、tsd_remove_nominal等第一个入参tsd_t *tsd其实就是上图中的struct tsd_s这个结构体的指针:

上图中还有一个相关的定义是:

tsdn_s其实也是一样的struct tsd_s结构体的指针:

定义一个tsdn_t是为了和tsd_t来区分,tsdn_t是可以为NULL的,而tsd_t指针是由tls机制直接获取到的struct tsd_s数据的指针,如下图在tsd_tls.h里有定义:

而刚才说的tsd_fetch_slow、tsd_state_set、tsd_add_nominal、tsd_remove_nominal这些函数的第一个入参tsd_t *tsd实际上都是通过类似如下截图的函数tsd_get来获取到的:

所以,很显然它的地址是不可能是NULL的。相关的注释如下:

对于入参是tsdn_t *tsdn的函数如iallocztm等而言,传入TSDN_NULL和非NULL做区分可以用来表示特殊的含义,如下图:

2.2.4 详细分析一下TSD_DATA_SLOW、TSD_DATA_FAST、TSD_DATA_SLOWER这几个宏

在tsd模块的实现里,TSD_DATA_SLOW、TSD_DATA_FAST、TSD_DATA_SLOWER这三个宏可以说是关键。我们以TSD_DATA_SLOW宏为例,搜索后可以发现,它被反复的使用:

而且每次使用,它都有实际不同的含义:

我们分别来展开一下:

tsd.h里的第一处TSD_DATA_SLOW是在定义struct tsd_s这个结构体时:

TSD_DATA_SLOW展开是受#define O(n, t, nt)的影响的:

所以在struct tsd_s {的定义里,O(n, t, nt) 被定义成t TSD_MANGLE(n)

而TSD_MANGLE(n)被定义成(为了方便调试缩短了变量名,见 2.1.2 里的说明):

所以在struct tsd_s {的定义里就是声明了一下结构体里的成员,但是名字要加一个头。

再看第二处TSD_DATA_SLOW的使用,如下图,定义O是一个p_get_unsafe结尾的一个函数:

所以上面的TSD_DATA_SLOW展开就是定义了获取tsd_s结构体里的DATA_SLOW部分里的成员变量一个个的获取函数

再看第三处,和第二处差不多,是定义了获取tsd_s结构体里的DATA_SLOW部分里的成员变量一个个的带tsd的state的assert检查的函数(关于tsd的state的简要说明见 2.2.5 一节):

再看第四处,也和第二、第三处差不多,是定义了获取tsd_s结构体里的DATA_SLOW部分里的成员变量一个个的带入参检查的获取函数,因为入参是tsdn_t*,是可能是NULL的(在 2.2.3 里有说明):

第五处及以后就不一一展开了。

2.2.5 tsd的state的minimal和nominal

在这一章的最后,我们涉及一下tsd模块里的函数经常会碰到tsd的state有关的minimal和nominal的区别。

tsd里除了变量定义一块以外,还有一个tsd的state的状态维护逻辑。这篇博客先不涉及过深的状态差异上的细节,先讲提及最常见的tsd的state状态,即nominal状态。

tsd的state的定义在tsd.h里:

上图中红色框出的是最常见的nominal状态,已经初始化完了且是快速路径的是这个状态。

上面的三个状态0,1,2,到2为止,都是属于泛nominal状态,表示的是线程不处于创建和销毁时期而导致tsd“不完整”的状态。

nominal在jemalloc里的大致意思就是某种理想或者预期的分配方式,那对于内存分配,理想或者预期就是能分配效率比较快也就是快速路径的状态。

三、从tsd模块实现中可以借鉴的一些编码技巧

3.1 把不同场景高概率一起用到的数据放在一起连续的进行定义,从而增加cache的命中率

在上面 2.2.3 里讲到的tsd模块按照TSD_DATA_SLOW、TSD_DATA_FAST、TSD_DATA_SLOWER定义不同的数据块内容,虽然最终在一个结构体里,但是它们的定义是连续的,从而让数据所在的内存上的区域更容易临近,从而提到cache的命中率

3.2 通过define和undef宏定义里所依赖的宏,实现批量成员变量定义和批量函数定义

在上面的 2.2.4 一节里讲到,通过重新define和undef O(n, t, nt)来配合TSD_DATA_SLOW、TSD_DATA_FAST、TSD_DATA_SLOWER来实现批量的函数和成员变量的定义,这种宏操作可以用于简化一些重复冗余代码,方便统一化维护和修改

3.3 结构体指针的定义通过typedef不同的类型做代码直观上的轻度“解耦”,可用于体现一些入参范围的差异,如nullable和non-nullable

在 2.2.3 里我们讲到了 tsdn_t的定义是增加了NULL可能的tsd_t,我们可以借鉴这样的定义方式,来方便一些模块函数在参数传入需要做区分时的编程上的一定的解耦,方便后期的维护,也从代码里直观察觉到差异,避免参数各个场景下的误用和逻辑上的误判

相关文章:

jemalloc 5.3.0的tsd模块的源码分析

一、背景 在主流的内存库里,jemalloc作为android 5.0-android 10.0的默认分配器肯定占用了非常重要的一席之地。jemalloc的低版本和高版本之间的差异特别大,低版本的诸多网上整理的总结,无论是在概念上和还是在结构体命名上在新版本中很多都…...

【Convex Optimization Stanford】Lec3 Function

【Convex Optimization Stanford】Lec3 Function 前言凸函数的定义对凸函数在一条线上的限制增值扩充? 一阶条件二阶条件一些一阶/二阶条件的例子象集和sublevel set关于函数凸性的扩展(Jesen Inequality)保持函数凸性的操作非负加权和 & 仿射函数的…...

深入 Rollup:从入门到精通(三)Rollup CLI命令行实战

准备阶段:初始化项目 初始化项目,这里使用的是pnpm,也可以使用yarn或者npm # npm npm init -y # yarn yarn init -y # pnpm pnpm init安装rollup # npm npm install rollup -D # yarn yarn add rollup -D # pnpm pnpm install rollup -D在…...

wangEditor富文本编辑器,Laravel上传图片配置和使用

文章目录 前言步骤1. 构造好前端模版2. 搭建后端存储3. 调试 前言 由于最近写项目需要使用富文本编辑器,使用的是VUE3.0版本所以很多不兼容,实际测试以后推荐使用wangEditor 步骤 构造好前端模版搭建后端存储调试 1. 构造好前端模版 安装模版 模版安…...

chrome源码剖析—进程通信

Chrome 浏览器采用多进程架构(multi-process architecture),这种架构使得每个浏览器标签、扩展、插件、GPU 渲染等都在独立的进程中运行。为了确保不同进程之间的高效通信,Chrome 使用 进程间通信(IPC, Inter-Process …...

JJJ:linux时间子系统相关术语

文章目录 墙上时间内核管理的各种时间无时钟滴答模式(tickless mode 或 no-tick mode)简要介绍具体实现动态时钟滴答 Dynamic Ticks完全无时钟滴答(Full Tickless) nohz sleep单触发模式 oneshot mode 墙上时间 真实世界的真实时…...

0 基础学运维:解锁 K8s 云计算运维工程师成长密码

前言:作为一个过来人,我曾站在技术的门槛之外,连电脑运行内存和内存空间都傻傻分不清,完完全全的零基础。但如今,我已成长为一名资深的k8s云计算运维工程师。回顾这段历程,我深知踏上这条技术之路的艰辛与不…...

大一计算机的自学总结:位运算的应用及位图

前言 不仅异或运算有很多骚操作,位运算本身也有很多骚操作。(尤其后几个题,太逆天了) 一、2 的幂 class Solution { public:bool isPowerOfTwo(int n) {return n>0&&n(n&-n);} }; 根据二进制表示数的原理&#…...

计算机毕业设计Django+Tensorflow音乐推荐系统 机器学习 深度学习 音乐可视化 音乐爬虫 知识图谱 混合神经网络推荐算法 大数据毕设

温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...

AI 图片涌入百度图库

在这个信息爆炸的时代,我们习惯了通过搜索引擎来获取各种想要的信息和图片。然而,现在打开搜索引擎看到的却是许多真假难辨的信息——AI图片,这部分数据正以惊人的速度涌入百度图库,让小编不禁想问:未来打开百度图库不…...

可爱狗狗的404动画页面HTML源码

源码介绍 可爱狗狗的404动画页面HTML源码,源码由HTMLCSSJS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行效果 效果预览 源码获取 可爱狗狗的404动画页面HTML源码...

【微服务与分布式实践】探索 Dubbo

核心组件 服务注册与发现原理 服务提供者启动时,会将其服务信息(如服务名、版本、所在节点的网络地址等)注册到注册中心。服务消费者则可以从注册中心发现可用的服务提供者列表,并与之通信。注册中心会存储服务的信息&#xff0c…...

OpenCSG月度更新2025.1

1月的OpenCSG取得了一些亮眼的成绩 在2025年1月,OpenCSG在产品和社区方面继续取得了显著进展。产品方面,推出了AutoHub浏览器自动化助手,帮助用户提升浏览体验;CSGHub企业版功能全面升级,现已开放试用申请&#xff0c…...

C++封装红黑树实现mymap和myset和模拟实现详解

文章目录 map和set的封装map和set的底层 map和set的模拟实现insertiterator实现的思路operatoroperator- -operator[ ] map和set的封装 介绍map和set的底层实现 map和set的底层 一份模版实例化出key的rb_tree和pair<k,v>的rb_tree rb_tree的Key和Value不是我们之前传统意…...

二次封装的方法

二次封装 我们开发中经常需要封装一些第三方组件&#xff0c;那么父组件应该怎么传值&#xff0c;怎么调用封装好的组件原有的属性、插槽、方法&#xff0c;一个个调用虽然可行&#xff0c;但十分麻烦&#xff0c;我们一起来看更简便的方法。 二次封装组件&#xff0c;属性怎…...

消息队列篇--通信协议篇--网络通信模型(OSI7层参考模型,TCP/IP分层模型)

一、OSI参考模型&#xff08;Open Systems Interconnection Model&#xff09; OSI参考模型是一个用于描述和标准化网络通信功能的七层框架。它由国际标准化组织&#xff08;ISO&#xff09;提出&#xff0c;旨在为不同的网络设备和协议提供一个通用的语言和结构&#xff0c;以…...

Python实现U盘数据自动拷贝

功能&#xff1a;当电脑上有U盘插入时&#xff0c;自动复制U盘内的所有内容 主要特点&#xff1a; 1、使用PyQt5创建图形界面&#xff0c;但默认隐藏 2、通过CtrlAltU组合键可以显示/隐藏界面 3、自动添加到Windows启动项 4、监控USB设备插入 5、按修改时间排序复制文件 6、静…...

汇编的使用总结

一、汇编的组成 1、汇编指令&#xff08;指令集&#xff09; 数据处理指令: 数据搬移指令 数据移位指令 位运算指令 算术运算指令 比较指令 跳转指令 内存读写指令 状态寄存器传送指令 异常产生指令等 2、伪指令 不是汇编指令&#xff0c;但是可以起到指令的作用&#xff0c;伪…...

DeepSeek理解概率的能力

问题&#xff1a; 下一个问题是概率问题。乘车时有一个人带刀子的概率是百分之一&#xff0c;两个人同时带刀子的概率是万分之一。有人认为如果他乘车时带上刀子&#xff0c;那么还有其他人带刀子的概率就是万分之一&#xff0c;他乘车就会安全得多。他的想法对吗&#xff1f;…...

AI 浪潮席卷中国年,开启科技新春新纪元

在这博主提前祝大家蛇年快乐呀&#xff01;&#xff01;&#xff01; 随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;其影响力已经渗透到社会生活的方方面面。在中国传统节日 —— 春节期间&#xff0c;AI 技术也展现出了巨大的潜力&#xff0c;为中国年带…...

AI时代的网络安全:传统技术的落寞与新机遇

AI时代的网络安全&#xff1a;传统技术的落寞与新机遇 在AI技术飞速发展的浪潮中&#xff0c;网络安全领域正经历着前所未有的变革。一方面&#xff0c;传统网络安全技术在面对新型攻击手段时逐渐显露出局限性&#xff1b;另一方面&#xff0c;AI为网络安全带来了新的机遇&…...

可以称之为“yyds”的物联网开源框架有哪几个?

有了物联网的发展&#xff0c;我们的生活似乎也变得更加“鲜活”、有趣、便捷&#xff0c;包具有科技感的。在物联网&#xff08;IoT&#xff09;领域中&#xff0c;也有许多优秀的开源框架支持设备连接、数据处理、云服务等&#xff0c;成为被用户们广泛认可的存在。以下给大家…...

线程局部存储tls的原理和使用

一、背景 tls即Thread Local Storage&#xff0c;也就是线程局部存储&#xff0c;可在进程内&#xff0c;多线程按照各个线程分开进行存储。对于一些与线程上下文相关的变量&#xff0c;可放到tls中&#xff0c;减少多线程之间的数据同步的开销。 有人可能会问&#xff0c;我…...

RK3588平台开发系列讲解(ARM篇)ARM64底层中断处理

文章目录 一、异常级别二、异常分类2.1、同步异常2.2、异步异常三、中断向量表沉淀、分享、成长,让自己和他人都能有所收获!😄 一、异常级别 ARM64处理器确实定义了4个异常级别(Exception Levels, EL),分别是EL0到EL3。这些级别用于管理处理器的特权级别和权限,级别越高…...

CAN总线

1. 数据帧&#xff08;Data Frame&#xff09; 数据帧是 CAN 总线中最常用的帧类型&#xff0c;用于传输实际的数据。其结构如下&#xff1a; 起始位&#xff08;Start of Frame, SOF&#xff09;&#xff1a;标志帧的开始。标识符&#xff08;Identifier&#xff09;&#x…...

qwen2.5-vl:阿里开源超强多模态大模型(包含使用方法、微调方法介绍)

1.简介 在 Qwen2-VL 发布后的五个月里&#xff0c;众多开发者基于该视觉语言模型开发了新的模型&#xff0c;并向 Qwen 团队提供了极具价值的反馈。在此期间&#xff0c;Qwen 团队始终致力于打造更具实用性的视觉语言模型。今天&#xff0c;Qwen 家族的最新成员——Qwen2.5-VL…...

python实现dbscan

python实现dbscan 原理 DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一个比较有代表性的基于密度的聚类算法。它将簇定义为密度相连的点的最大集合&#xff0c;能够把具有足够高密度的区域划分为簇&#xff0c;并可在噪声的空间数据库中发现任意形…...

学习数据结构(3)顺序表

1.动态顺序表的实现 &#xff08;1&#xff09;初始化 &#xff08;2&#xff09;扩容 &#xff08;3&#xff09;头部插入 &#xff08;4&#xff09;尾部插入 &#xff08;5&#xff09;头部删除 &#xff08;这里注意要保证有效数据个数不为0&#xff09; &#xff08;6&a…...

正在更新丨豆瓣电影详细数据的采集与可视化分析(scrapy+mysql+matplotlib+flask)

文章目录 豆瓣电影详细数据的采集与可视化分析(scrapy+mysql+matplotlib+flask)写在前面数据采集0.注意事项1.创建Scrapy项目`douban2025`2.用`PyCharm`打开项目3.创建爬虫脚本`douban.py`4.修改`items.py`的代码5.修改`pipelines.py`代码6.修改`settings.py`代码7.启动`doub…...

wx043基于springboot+vue+uniapp的智慧物流小程序

开发语言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#…...