dlmalloc 2.8.6 源码详解(2)

dlmalloc说明及代码 dlmalloc是目前一个十分流行的内存分配器,其由Doug Lea(主页为http://gee.cs.oswego.edu/)从1987年开始编写,到目前为止,最新版本为2.8.3(可以从ftp://g.oswego.edu/pub/misc/malloc.c获取),由于其高效率等特点被广泛的使用(比如一些linux系统等用的就是dlmalloc或其变形,比如ptmalloc,主页为http://www.malloc.de/en/index.html)和研究(各位可以搜索关键字“GCspy”)。 dlmalloc的实现只有一个源文件(还有一个头文件),大概5000行,其内注释占了大量篇幅,由于有这么多注释存在的情况下,表面上看上去很容易懂,的确如此,在不追求细节的情况,对其大致思想的确很容易了解(没错,就只是了解而已),但是dlmalloc作为一个高品质的佳作,实现上使用了非常多的技巧,在实现细节上不花费一定的精力是没有办法深入理解其为什么这么做,这么做的好处在哪,只有当真正读懂后回味起来才发现它是如此美妙。 lenky0401个人博客将陆续推出对dlmalloc的解析(针对Doug Lea Malloc的最新版Version 2.8.3,未做说明的情况下以32位平台,8字节对齐作为假定平台环境设置考虑),由于个人水平有限,因此也不能完全保证对dlmalloc的所有理解都准备无误, 但是所有内容均出自个人的理解而并非存心妄自揣测来愚人耳目,所以如果读者发现其中有什么错误,请勿见怪,如果可以则请来信告之,并欢迎来信讨论(lenky0401@163.com)。 这一系列文章是lenky0401在看完dlmalloc的大部分代码后的再总结,不能保证对dlmalloc的整体完全把握,贴出这些只是希望可以提前收到对此有研究的网友的指点,以便在最后对这一系列文章整理而形成的PDF文档中错误能少一些。至于对于现在贴出来的内容中包含的错误给大家造成的不便提前说声抱歉。:) 描述的内容不会包含dlmalloc全部代码,但会将这其中涉及到的一些技巧尽量讲出,我相信对dlmalloc源代码不感兴趣的朋友也可以学到这些独立的技巧而使用在自己的编程实践中。:) 最后,转载请保留本博客地址连接[http://lenky0401.cublog.cn],谢谢。 立即下载

本文章由vector03原创, 转载请注明出处.

邮箱地址: mmzsmm@163.com, 欢迎来信讨论.

 

2. 标记结构

本章节将介绍基本的内存标记结构,包括chunk, tree chunk, sbin, tbin, segment, mstate等.这些重要的机构组成了dlmalloc分配算法的基础.

2.1 chunk

chunk是dlmalloc中最基本的一种结构,它代表了一块经过划分后被管理的内存单元. dlmalloc所有对内存的操作几乎都聚焦在chunk上.需要注意的是, chunk虽然看似基础,但不代表它能管理的内存小.事实上chunk被划分为两种类型,小于256字节的称为small chunk,而大于等于256字节的被称为tree chunk.

2.1.1 chunk布局

在dlmalloc的源码中有一幅用字符画成的示意图,套用Doug Lea本人的话说 “is misleading but accurate and necessary”.初次接触这种结构划分会觉得既古怪又别扭. 因此,接下来的几节内容需要认真体会,让大脑适应这种错位的思考.

对于一个已分配chunk, 它在内存中可能是这个样子,

上图为了便于理解特意使用了两种颜色来描述,蓝色区域的部分代表当前的已分配chunk,而黄色区域代表上一个和下一个chunk的部分区域.

解释一下其中的含义, 从蓝色区域开始看, 在已分配chunk的开始记录当前chunk的size信息,同时在最后两个bit位分别记录当前chunk和前一个chunk是否被使用,简称为C和P两个bit位.之所以可以做到这一点,是因为在dlmalloc中所有的chunk size至少对齐到大于8并以2为底的指数边界上.这样,至少最后3位都是0,因此这些多余的bit位就可以拿来记录更多的信息. size信息后面是payload部分,显然,当前chunk的使用信息也会记录在下一个chunk开始的P位上.

而对于一个空闲chunk, 其内存布局应该是这样的,

与之前的一致, 蓝色区域代表当前空闲chunk, 黄色区域代表相邻的前后chunk.可以看到空闲chunk与之前的区别在于开始的size后多了next和prev指针,它们把具有相同大小的空闲chunk链接到一起.另一个区别是,在空闲chunk最后同样记录该chunk的大小信息.那么为什么同样的信息要记录两次呢?在下一个小节中会解释这个问题.

另外, 还有一点需要说明的是,空闲chunk的相邻chunk必然是已分配的chunk.因为如果存在相邻两个chunk都是空闲的,那么dlmalloc会把它们合并为一个更大的chunk.

2.1.2 边界标记法(Boundary Tag)

上一节中介绍的chunk布局其实只是理论上的东西,而实现它使用了被称为边界标记法 (boundary tag)的技术.据作者说,此方法最早是大神Knuth提出的.实现边界标记法使用了名为malloc_chunk的结构体,它的定义如下,

该结构体(以后简称mchunk)由四个field组成.最开始是prev_foot,记录了上一个邻接chunk的最后4个字节.接下来是head,记录当前chunk的size以及C和P位.最后两个是fd, bk指针,只对空闲chunk起作用,用于链接相同大小的空闲chunk.

为了避免读者感到困惑, 在上一节的图中并没有画出对应的mchunk, 现在补充完整如下,

上图用不同颜色画了几个连续交错的chunk,并故意在中间断开,标注出mchunk以及chunk的实际范围,由此得到如下的结论,

1.       mchunk的作用是将连续内存划分为一段段小的区块, 并在内部保留这些区块的信息.

2.       mchunk最后的fd, bk是可以复用的,对于空闲chunk它们代表链接指针,而已使用chunk中这两个field实际上存放的是payload数据.

3.       mchunk与chunk不是一个等同的概念.这一点是容易让人混淆和困惑的. mchunk只是一个边界信息,它实际上横跨了两个相邻chunk.尽管一般认为mchunk可以指代当前的chunk,因为你可以从它推算出想要的地址.但从逻辑上,它既不代表当前chunk也不代表prev chunk.

4.       prev_foot字段同样是一个可复用的字段. 一般情况下它有三种含义,如果前一个相邻chunk是空闲状态,它记录该chunk的大小(图中mchunk C).其目的就是你可以很方便的从当前chunk获得上一个相邻chunk的首地址,从而快速对它们进行合并.这也就是上一小节介绍的空闲chunk会在head和footer存在两个chunk size的原因,位于footer的size实际上保存在下一个mchunk中.如果前一个相邻chunk处于in used状态,那么该字段可能有两种情况.一种情况是FOOTERS宏为1,这时它保存一个交叉检查值,用于在free()的时候进行校验.如果该宏为0,则它没有多余的含义,单纯只是前面chunk的payload数据.

5.       最后还有一点需要注意的是, 尽管前面提到所有chunk size都是对齐到至少等于8的2的指数.但这不意味着mchunk就对齐到这一边界上,因为如前所述mchunk和chunk是两码事.我本人最早在看这部分代码时曾天真的以为mchunk也是对齐的,结果到后面居然完全看不懂,后来才发现这家伙根本没有对齐.

到目前为止, 已经了解了dlmalloc的边界标记法是如何实现的.可能有人会对此感到不以为然,作者为什么要把代码写成这个样子呢?其实,要理解这个意图请换位思考一下,如果实现一个类似的东西,你会怎么写呢?人们很快会发现,不按照这种方式设计,想要达到同样目的几乎是很困难的.因为一个chunk在头和尾存在head和footer(也可能不存在footer),中间是一片长度无法确定的区域.假设按照正常从头到尾的顺序写,这个结构体中间填充多长的内容是没法确定的.因此, Doug Lea巧妙的把除了payload之外的overhead部分合并在一起,作为boundary tag来分割整个内存区域,既能做到很方便的计算,又准确地表达了chunk的结构.

2.1.3 chunk操作

针对mchunk的设计,源码中定义了大量的宏来对其进行操作.由于数量很多加上嵌套,对于阅读源码会造成不小的障碍,因此这里会对一些常用宏进行梳理和简单讲解.

定义size_t的大小和bit位数.注意, dlmalloc中对size_t规定为必须为无符号类型,且与指针类型(void*)等宽度.因此如果目标平台还在使用有符号的size_t,只能使用较旧版本的dlmalloc.

常量定义, 这里使用size_t作为强制类型是为了避免在某些平台上出现错误.

对齐边界和对齐掩码, 边界默认定义为两倍指针宽度, 当然还可以修改的更大,但必须以2为底的指数.有关对齐掩码相关知识请参考1.4.1节.

判断给定地址是否对齐在边界上,原理同样在1.4.1节中解释,不再赘述.

计算给定地址需要对齐的偏移量,请参考1.4.3节中的介绍.

chunk size(实际上是mchunk size,后面不再特意说明)以及overhead大小.注意,如果FOOTERS等于1, overhead将多出4个字节,其实就是在chunk最后放置交叉检查项多出的负载.另外,不管是否有FOOTERS, chunk size本身是不变的.

最小chunk大小. dlmalloc中即使调用malloc(0)也是会分配内存的.这种情况下完全不考虑用户payload了,仅仅将chunk size做了对齐.该值的意义在于,这是dlmalloc中除了mmap chunk以外的最坏负载损耗.

这是两个最常用的宏之一, 在chunk和用户地址之前切换.

该宏的意思是, 将指定chunk的用户地址对齐,返回对齐后的新chunk地址.理解很容易,从chunk获取用户地址,计算对齐偏移,再移动chunk指针.从这里可以看到, chunk中对齐的并非是mchunk指针,而是用户地址.

将用户请求的内存值转化成实际的内部大小.该宏也是常用宏之一,请求大小先加上overhead(根据FOOTERS而有所不同),再对齐到边界上.

该宏是对上面一系列宏的封装, 如果用户请求小于最小请求, 直接使用最小chunk大小,否则认为正常,转化成内部可用大小.

上面这一组定义了C位和P位,其中FLAG4_BIT并没有实际用途,只是作为未来的扩展.

测试C和P位,分别用掩码做与运算.着重说一下最后两个判断. is_inuse是用C和P的掩码分别测试,然后与P的掩码对比.有人会问这个直接用前面的cinuse不就好了吗?因为存在一种特殊情况,就是被mmap出来的chunk是不见得有邻接chunk的,所以其C和P都被置0. is_inuse就是为了判断包括mmap chunk在内的所有类型chunk的使用情况.理解了这个, is_mmapped就很容易理解了.

计算指定chunk的大小,清除最后3bit后得到的就是size.

对P位的操作.

这是两个计算偏移量的宏, 返回结果被认为是mchunk, 一般用作chunk切割.

这两个也是非常重要的宏. 分别用来计算前一个或后一个邻接chunk的首地址. next_chunk先获取当前chunk的size作为偏移量,再移动chunk指针. prev_chunk则是直接加上前一个chunk的footer作为偏移量.需要注意的是, prev_chunk仅仅适用于前一个邻接chunk为空闲块的情况.如前所述,非空闲chunk这里放置的可能是用户数据或者交叉检查项.实际上这个宏就是用于free时试图与前一个free chunk合并时的判断.

获取下一个chunk的P位,应该与当前chunk的C是一致的.该宏一般用作交叉检查项.

获取和设置当前chunk的footer,因为footer被放在下一个邻接chunk的prev_foot中,因此需要加上size作为偏移量.

该宏是个复合操作, 用于对free chunk进行设置.因为free chunk在head和footer都保存其size,所以首先将其head中写入size.又因为free chunk的P一定是1(否则会与前面合并),因此还需要与P掩码进行一次位与.接着,利用前面的set_foot宏在footer中同样写入size.

这个宏与上面的区别在于多了一个next chunk的P位维护.因为是针对free chunk, next chunk的P需要置0.

2.1.4 tree chunk

之前介绍的chunk其实都属于小型chunk,而较大型的chunk是通过名为malloc_tree_chunk的结构体来描述的.

同mchunk类似tree chunk(以后简称tchunk)开始的field是一模一样的,这就保证了两种类型在基础结构上具有较好的兼容性,降低了代码编写难度. tchunk与前者的区别在于管理上使用不同的结构. mchunk是通过双链表组织起来的,而tchunk使用了一种树形结构,在介绍分箱时会详细说明.因此tchunk中child分别代表了左右子树节点, parent代表父节点, index代表该chunk所在分箱的编号.而fd, bk与mchunk一致,都是用于链接相同size的chunk.另外,需要说明的是,上述结构体字段同样只适用于free chunk,在used chunk上它们都是可复用的.

 

dlmalloc源码解析 从源码级别详细介绍dlmalloc内存管理思想,尤其针对算法和代码技巧角度剖析dlmalloc 立即下载

相关推荐

AI时代,程序员何去何从?别慌,看完这篇你就明白了

AI时代程序员的发展方向 摘要:随着AI代码助手的普及,程序员行业面临变革。本文通过实际案例展示AI写代码的能力与局限:AI能生成基础功能代码(如RESTful API、数据处理脚本),但缺乏业务理解、系统设计和复杂逻辑处理能力。程序员的核心价值在于需求分析、架构设计、性能优化等高层能力。未来程序员应: 掌握AI工具提升效率 专注于创新和架构设计 培养业务理解能力 持续学习新技术 AI不会取代程序员,但会淘汰不会使用AI的程序员。建议开发者拥抱AI工具,将其作为助手而非威胁,聚焦高价值工作。

yunque_xianguang的博客 908

dlmalloc、ptmalloc与glibc堆漏洞利用

本文主要介绍dlmalloc、ptmalloc的详细原理,并分析几个常见的漏洞利用方法。

有价值炮灰 2026

STM32项目实战_基于STM32F103的智能药箱设计与实现(硬件详解+软件逻辑+调试要点)

本文详细介绍了基于STM32F103的智能药箱设计与实现,涵盖硬件设计、软件逻辑和调试要点。项目核心功能包括精准提醒、药品管理和远程监控,采用STM32单片机作为主控,结合光电开关、蓝牙模块等实现智能化管理。文章还分享了电路图设计、程序优化及常见问题解决方案,为嵌入式开发爱好者提供实用参考。

weixin_28717683的博客 306

dlmalloc(一)

我们写过很多C程序了,经常会分配内存。记得刚学C语言时老师说过,可以向两个地方申请内存:一个是栈、一个是堆。小块内存向栈申请,函数调用结束后程序会自动释放内存。大块内存向堆申请,记得一定要自己释放,否则会造成内存泄漏。向堆申请内存直接调用malloc()就可以了,参数是你申请的内存量。释放内存时直接调用free()就可以了,参数是内存块指针。 看似平静的海面,海底则波涛汹涌。当时还没有学操作系统

ycnian 1万+

高精度SAR ADC设计实战:从建模到版图的16位1MSPS实现

本文详细介绍了16位1MSPS高精度SAR ADC的设计过程,从建模到版图实现的完整流程。重点探讨了分段电容阵列设计、校准算法实现及版图匹配等关键技术,展示了如何在180nm工艺下实现92.5dB SNDR和109.6dB SFDR的高性能指标。文章特别强调了整数桥接电容设计对提升匹配精度的关键作用,为高精度模数转换器设计提供了实用参考。

weixin_33724046的博客 438

西门子 G120 变频器报文

G120报文

mmxxoo_xxmmp的博客 8092

dlmalloc 图解

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34007886的博客 1331

TPC好像是这么回事儿

TPC(Transmit Power Control)发送功率控制,本觉得就是控制一下发送功率,原理很简单,但看原版协议死活每搞懂什么意思,恼羞成怒!!!! 后来又看了一些贴子和cisco的相关功能介绍,再回头看协议,好像是这么一回事: 1、所谓TPC,是AP控制STA的发送功率的一种手段。在802.11d中,已定义了使用Country Element传递区域无线通信规定的信道和最大发送功率信息: 通过获取这些信息,STA可以确定自己应该遵守什么规则,可以用什么发送功率在哪些信道上通信。 2

两只勤劳的蜜蜂 8630

DLmalloc 内存分配算法

<br />dlmalloc由Doug Lea编写的内存分配算法<br />     <br />(1)mspace_malloc/mspace_free<br />(2) dlmalloc/dlfree<br />        <br />1.边界标记<br />2.空闲块分箱:2个分箱数组<br />    (1)小块空闲块大小(0-256):数组元素-空闲块链表<br />    (2)大块空闲块大小(>256):数组元素-空闲块树<br />3. 空闲段<br />   <br />内存分配过程:

tuhuolong的专栏 2824

Win11下DCMTK的Visual Studio 2022配置教程

最近有个新需求,需要完成读取和解析DICOM数据相关的SDK

qq_45797625的博客 3262

Openclaw错误分析与解决方案之:Agent couldn’t generate a response.

Openclaw错误分析与解决方案之:Agent couldn't generate a response. Note: some tool actions may have already been executed — please verify before retrying.

多媒体编程、网络编程、系统编程、网络安全编程、驱动编程 1318

探索 dlmalloc:一款高效的内存管理库

探索 dlmalloc:一款高效的内存管理库 是一个开源的、高度优化的 C 语言实现的动态内存分配器。它由 Doug Lea 在 1980 年代开发,并被广泛应用于各种操作系统和软件中。本文将为您介绍 dlmalloc 的基本功能、应用场景及其主要特点。 功能与用途 dlmalloc 提供了一组动态内存管理函数,以高效地处理程序中的内存分配需求。这些函数包括: malloc(size_t siz...

gitblog_00072的博客 900

QGis软件 —— 9、QGis - 由点绘制热力图来模拟人流量(绘制点方式、excel导入数据方式)

QGis软件 —— 9、QGis - 由点绘制热力图来模拟人流量(绘制点方式、excel导入数据方式)

1471

dlmalloc 2.8.6 源码详解(6)

基本上sys_alloc分为四个步骤, 1. 首先检查请求大小nb是否超出mmap_threshold的阈值. 如果是, 则放弃由分配器管理, 直接在mmap区开辟, 原因前面说过, 不再赘述. 2. 根据mspace设定及当前top space的使用情况, 向系统申请一块适当的内存. Dlmalloc按照下面的顺序由主到次开辟, 第一, 如果允许MORECORE, 则优先通过MORECORE开辟连续内存空间.

vector03的专栏 2544

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

dlmalloc 2.8.6 源码详解(3)

前面介绍过, dlmalloc将小于256字节的内存划分为small chunk, 256字节以上的划分为tree chunk.对这两种chunk的管理也采用不同方式. small chunk使用small bins管理,采用更精确的标记方法,而tree chunk用tree bins管理,较之使用相对粗放的管理方式.这种划分方法基于这样一种经验性的认知,即小块内存总是连续而频繁的分配,因此需要更加精确匹配,否则将产生时间和空间上的缺失,相反大块内存则往往一次性的分配,由此产生的代价和浪费相对较低.

vector03的专栏 3484

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

dlmalloc 2.8.6 源码详解(5)

本章节介绍dlmalloc的分配算法和实现. 由于存在多mspace的情况, dlmalloc使用了两套API. 一套对应默认的mspace, 以dl前缀开头, 如dlmalloc, dlrealloc等. 如果创建了自定义的mspace, 则使用mspace开头的API, 如mspace_malloc, mspace_realloc等. 但两套API在基础算法上是一致的. 我们就以默认的API为主要对象介绍.

vector03的专栏 3588

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

dlmalloc 2.8.6 源码详解(1)

本文章由vector03原创, 转载请注明出处. 邮箱地址

vector03的专栏 9367

dlmalloc 2.8.6 源码详解(4)

在dlmalloc的内部结构中,除了基础的chunk外,还存在一种粒度更粗的结构,称为区段(segment). 之所以需要额外引入这种数据结构是为了提升对非连续内存的管理能力. dlmalloc将连续内存划分到一个segment中管理,而段与段之间则是不连续的,所有的段都由一个mspace统一去管理.如果用户程序创建了多个mspace,这些mspace内部包含的segment有可能在地址上连续,但实际归属于不同的空间.

vector03的专栏 3947

dlmalloc 2.8.6 源码详解—[5]释放及实现

转载自:vector034 释放与实现释放过程相对分配就简单多了, 基本着重在chunk合并, top裁剪, segment释放上. dlmalloc中合并是减少外部碎片最有效的方法了.4.1 dlfree释放的主要过程就是根据用户传入的payload, 找到chunk指针, 然后分别检查前一个和后一个chunk是否可以合并. 这里唯一需要注意的就是与dv和top这些特殊chunk的交互.基本流程如

杏林小轩 738

dlmalloc 2.8.6 源码详解(7)

本文章由vector03原创, 转载至[vector03](https://blog.csdn.net/vector03/article/details/41314055)释放过程相对分配就简单多了基本着重在chunk合并, top裁剪, segment释放上. dlmalloc中合并是减少外部碎片最有效的方法了释放的主要过程就是根据用户传入的payload,找到chunk指针然后分别检查前一个和后一个chunk是否可以合并这里唯一需要注意的就是与dv和top。

firebuffer的专栏 105
上一篇: dlmalloc 2.8.6 源码详解(1)
下一篇: dlmalloc 2.8.6 源码详解(3)
vector03
博客等级 码龄16年 62粉丝 16原创
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值