Glibc 的malloc源代码分析

glibc中malloc源码分析 学了这么久堆漏洞了,我想应该把的和源码解析写一下了,希望能帮助一下刚上路的师傅,同时也巩固一下自身知识。我们平时写程序的时候,某些变量可能需要在开始就分配内存,这些内存是不可避免的。那么这些内存就是静态分配的,当程序编译完成之后,它就确定了占用这么多的内存。但是有时候,实际问题的规模没有预期那么大,我们不一定需要很大的内存,如果每次都按最大考虑那么就有很大一部分内存是被浪费的,这就是静态分配内存的弊端,虽然咱打acm的时候都是静态分配的,但是这没啥,因为每个问题不要超过它的总内存上限问题就不大(狗头。但是在 阅读详情

Glibc 的 malloc 源代码分析

有人写了一个测试程序

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>

main()
{
  int alloc_time = 20000;
  char* a[alloc_time];
  char* b[alloc_time];
for(int j=0; j<5; j++)
{
  for(int i=0; i<alloc_time; i++)
  {
    a[i] = (char*)malloc(52722);
    memset(a[i], 1, 52722);
    b[i] = (char*)malloc(1);
    memset(b[i], 1, 1);
  }
  for(int i=0; i<alloc_time; i++)
  {
    free(a[i]);
    free(b[i]);
  }
}
  while(1)
  {
    sleep(10);
  }
}

发现 该程序在测试机上运行会占用 1G 内存,不释放,为了解决这个问题,特别去研究了一下glibc 中malloc 的源代码。

 

 

 

 

一.对于小于 128k 的块在 heap 中分配。

1. 堆是通过 brk 的方式来增长或压缩的,如果在现有的堆中不能找到合适的 chunk ,会通过增长堆的方式来满足分配,如果堆顶的空闲块超过一定的阀值会收缩堆,所以只要堆顶的空间没释放,堆是一直不会收缩的。

2. 堆中的分配信息是通过两个方式来记录。

第一.是通过 chunk 的头, chunk 中的头一个字是记录前一个 chunk 的大小,第二个字是记录当前 chunk 的大小和一些标志位,从第三个字开始是要使用的内存。所以通过内存地址可以找到 chunk ,通过 chunk 也可以找到内存地址。还可以找到相邻的下一个 chunk ,和相邻的前一个 chunk 。一个堆完全是由 n 个 chunk 组成 。

第二.是由 3 种队列记录 ,只用空闲 chunk 才会出现在队列中,使用的 chunk 不会出现在队列中。如果内存块是空闲的它会挂到其中一个队列中,它是通过内存复用的方式,使用空闲 chunk 的第 3 个字和第 4 个字当作它的前链和后链(变长块是第 5 个字和第 6 个字),省的再分配空间给它。

第一种队列是 bins , bins 有 128 个队列,前 64 个队列是定长的,每隔 8 个字节大小的块分配在一个队列,后面的 64 个队列是不定长的,就是在一个范围长度的都分配在一个队列中。所有长度小于 512 字节(大约)的都分配在定长的队列中 。后面的 64 个队列是变长的队列,每个队列中的 chunk 都是从小到大排列的。

第二种队列是 unsort 队列(只有一个队列),(是一个缓冲)所有 free 下来的如果要进入 bins 队列中都要经过 unsort 队列。

第三种队列是 fastbins ,大约有 10 个定长队列,(是一个高速缓冲)所有 free 下来的并且长度是小于 80 的 chunk 就会进入这种队列中。进入此队列的 chunk 在 free 的时候并不修改使用位,目的是为了避免被相邻的块合并掉。

3.malloc 的步骤

l         先在 fastbins 中找,如果能找到,从队列中取下后(不需要再置使用位为 1 了)立刻返回。

l         判断需求的块是否在小箱子 ( bins 的前 64 个 bin )范围,如果在小箱子的范围,并且刚好有需求的块,则直接返回内存地址;如果范围在大箱子( bins 的后 64 个 bin )里,则触发 consolidate 。(因为在大箱子找一般都要切割,所以要优先合并,避免过多碎片)

l         然后在 unsort 中取出一个 chunk ,如果能找到刚好和想要的 chunk 相同大小的 chunk ,立刻返回,如果不是想要 chunk 大小的 chunk ,就把他插入到 bins 对应的队列中去。转 3 ,直到清空,或者一次循环了 10000 次。

l         然后才在 bins 中找,找到一个最小的能符合需求的 chunk 从队列中取下,如果剩下的大小还能建一个 chunk ,就把 chunk 分成两个部分,把剩下的 chunk 插入到 unsort 队列中去,把 chunk 的内存地址返回。

l         在 topchunk (是堆顶的一个 chunk ,不会放到任何一个队列里的)找,如果能切出符合要求的,把剩下的一部分当作 topchunk ,然后返回内存地址。

l         如果 fastbins 不为空,触发 consolidate 即把所有的 fanbins 清空 (是把 fanbins 的使用位置 0 ,把相邻的块合并起来,然后挂到 unsort 队列中去),然后继续第 3 步。

l         还找不到话就调用 sysalloc ,其实就是增长堆了。然后返回内存地址。

4.free 的步骤

l         如果和 topchunk 相邻,直接和 topchunk 合并,不会放到其他的空闲队列中去。

l         如果释放的大小小于 80 字节,就把它挂到 fastbins 中去,使用位仍然为 1 ,当然更不会去合并相邻块。

l         如果释放块大小介于 80-128k ,把 chunk 的使用位置成 0 ,然后试图合并相邻块,挂到 unsort 队列中去,如果合并后的大小大于 64k ,也会触发 consolidate ,(可能是周围比较多小块了吧),然后才试图去收缩堆。(收缩堆的条件是当前 free 的块大小加上前后能合并 chunk 的大小大于 64k ,并且要堆顶的大小要达到阀值,才有可能收缩堆)

l         对于大于 128k 的块,直接 munmap

 

 

 

二.大于 128k 的块通过 mmap 的方式来分配。

 

 

 

 

根据以上的分析,我们可以得出为什么会还占用 1G 的内存。

测试程序有两重循环,内层循环先分配 1G ,然后全部释放,外层执行这个步骤 5 次,但为什么最后一次释放会不成功呢。

主要是因为按照这个程序分配后,内存变成由小块和大块交替出现,释放小块的时候,直接把小块放到 fastbins 中去,而且他的使用位还是 1 ,释放大块的时候,它试图合并相邻的块,但是和它相邻的块的使用位还是 1 ,所以它不能把相邻的块合并去来,而且释放的块的大小小于 64k ,也不会触发 consolidate ,即不会把 fastbins 清空 ,所以当所有的块都被释放完后,所有的小块都在 fastbins 里面,使用位都为 1 ,大块都挂在 unsort 队列里面。全部都无法合并。所以使用的堆更加无法压缩。

 

如果在外循环后面再分配 2000 字节然后释放的话,所有内存将全部清空。这是因为在申请 2000 字节的时候,由 malloc 的第二步,程序会先调用 consolidate ,即把所有的 fastbins 清空,同时把相邻的块合并起来,等到所有的 fastbins 清空的时候,所有的块也被合并去来了,然后调用 free2000 字节的时候,这块被将被合并起来 ,成为 topchunk ,并且大小远大于 64k ,所有堆将会收缩,内存归还给系统。

 

转帖自:http://blog.chinaunix.net/u3/94916/showart_1908306.html

glibc源码分析-malloc-free 简要分析malloc和free源码 阅读详情

相关推荐

glibc-2.23 sysmalloc函数代码分析

基础知识:    malloc_state 和 heap_info    heap 就是一块大的内存区域,若不是main_arena,heap是mmap创建的,main_arena是sbrk拓展得到的(拓展失败也会调用mmap) (由于main_arena的heap在内存开始处没有保存heap的info,所以和非main_arena的heap还有稍微有点区别的) malloc_state 结构体是用来管理bins和heap的结构体,(top chunk 指向的就是一个heap的可用区域)。 当我们从一个a

qq_34010404的博客 992

c++ malloc能给string_分析 Glibc 中的malloc/free 实现

本文使用 Zhihu On VSCode 创作并发布malloc 和 free 内部依赖的是GNU Allocator, 也叫Doug Lea的Allocator: http://gee.cs.oswego.edu/dl/html/malloc.html。这篇分析会主要注意Allocator是怎么管理内存的。它就像操作系统和用户中间的一层,扮演了一个内存池的角色。本篇源码分析主要基于github上...

weixin_39657521的博客 650

Glibc:浅谈 malloc() 函数具体实现

简介 源代码 __libc_malloc() _int_malloc() __libc_malloc() 分析 参数 __malloc_hook 全局钩子 ptmalloc_init 转入 _int_malloc() _int_malloc 分析 计算 chunk size 是否命中 fastbins 是否命中 smallbins 非 smallbins 则转入 malloc_co...

加号减减号的博客 9149

Glibc 的 malloc 源代码分析

Glibc 的 malloc 源代码分析 有人写了一个测试程序 #include #include #include #include main() {   int alloc_time = 20000;   char* a[alloc_time];   char* b[alloc_time]; for(int j=0; j {    for(int i=0;

wzb56的资料库 936

浅析基于glibc的malloc

最近看了几个malloc和free的问题,总结一下。 malloc和free由谁提供? 一般来讲,它们是C Standard Library提供的而不是由操作系统的内核实现。例如微软的是msvcrt,Linux下是glibc。当然也有第三方库函数,比如jemalloc、tcmalloc。所以每个malloc和free的实现都有所不同,而且这些实现和内核之间是保留有一定自由度的。比如每次mall

聚沙成塔 积水成渊 3963

glibc下malloc的理解

glibc下malloc的浅析

MIThebut的专栏 4251

glibc中malloc()的空间overhead

在linux下调用malloc()分配内存的时候,实际占用的内存与请求的内存尺寸的关系是什么呢,这个需要研究一下glibc中malloc()的实现。现在常见linux发行版中带的glibc中采用的都是Doug Lea的实现,下面的分析取自他的2.8.4版本的malloc.c。 glibc对内存的管理是以chunk为单位的,未分配的chunk之间用双向链表连接成一个环,遍历的时候用指针遍历...

weixin_34088598的博客 147

Glibc:浅谈 malloc_consolidate() 函数具体实现

简介 源代码 分析 0x00 - 堆未初始化则初始化 0x01 - 堆已初始化则清空 fastbin 总结 简介 malloc_consolidate() 函数是定义在 malloc.c 中的一个函数,用于将 fastbin 中的空闲 chunk 合并整理到 unsorted_bin 中以及进行初始化堆的工作,在 malloc() 以及 free() 中均有可能调用 m...

加号减减号的博客 1万+

malloc和free

昨天看见一位同学分享面试经历。 中间有这么一句话:”一是Java的内存分配原理与C/C++不同,C/C++每次采用malloc或new申请内存时都要进行brk和mmap等系统调用,而系统调用发生在内核空间,每次都要中断进行切换,这需要一定的开销“。 因为这个同学最终拿到了阿里offer,且这个回答得到了面试官”(面试官一直点头表示对我回答的赞同)嗯,看来你对这块的确掌握了“的回应,不知道是这位

yejing's utopia 4097

malloc源码分析glibc库

glibc内存管理ptmalloc源代码分析4.pdf

glibc内存管理ptmalloc源代码分析PDF

淘宝网的研发人员写的文档,对了解GNU C的内存分配机制有很大的帮助!

Glibc:浅谈 unlink 宏的具体实现

简介 源代码 分析 0x00 0x01 - 设置相邻 chunk 的 fd 或 bk 指针 0x02 - 特别处理 largebin 的 fd_nextsize 和 bk_nextsize 指针 总结 简介 unlink() 是一个宏,用于将某一个空闲 chunk 从其所处的 bin 中脱链。在 malloc_consolidate() 函数中将 fastbin 中的...

加号减减号的博客 1859

glibc内存管理ptmalloc源代码分析-高清PDF-pdf版

glibc内存管理ptmalloc源代码分析-电子资料-高清PDF版-pdf打印版

c malloc结构体_分析 Glibc 中的malloc/free 实现

本文使用 Zhihu On VSCode 创作并发布malloc 和 free 内部依赖的是GNU Allocator, 也叫Doug Lea的Allocator: http://gee.cs.oswego.edu/dl/html/malloc.html。这篇分析会主要注意Allocator是怎么管理内存的。它就像操作系统和用户中间的一层,扮演了一个内存池的角色。本篇源码分析主要基于github上...

weixin_39666931的博客 554

【扫地机器人】详细介绍扫地机器人软硬件测试和场景化测试

本文提出2025版扫地机器人全生命周期测试方案,涵盖实验室仿真、硬件台架、客户实景等全流程验证。测试以"清洁率≥95%、覆盖率≥98%、MTBF≥1000h"为核心指标,采用数字孪生与120套真实场景结合的双V模型。重点包括:传感器精度(LDS误差<±10mm)、清洁系统性能(10g粉尘吸入率≥99%)、动力续航(800次循环容量保持≥80%)等硬件测试;以及SLAM重定位(误差<5cm)、AI识别(mAP>92%)等软件验证。方案特别针对宠物家庭(毛发缠绕率≤3%)、

2501_92897788的博客 2280

Zynq UltraScale+ MPSoC-AMP(linux+裸机)

接着 Zynq UltraScale+ MPSoC-双核裸机AMP继续 平台工具:zcu106,vitis2020.2,petalinux2019.2 文章目录1.cpu1跑裸机2.cpu0跑linux2.1petalinux设置2.2 app3.生成BOOT.bin4.zcu106测试 1.cpu1跑裸机 参照Zynq UltraScale+ MPSoC-双核裸机AMP建立的工程进行修改。BSP中stdin与out修改为uart1,uart1给裸机用,uart0给linux用。 ddr空间裸机与linu

zhuxl24的博客 5195

面试官问:malloc(0)时程序会返回什么?

今天跟大家找了篇文章,主要是一个面试中的有趣问题,其实有些问题在开发中没有遇到过会很难回答出来,如果在面试过程中回答正确,皆大欢喜,拿到offer的概率更大;回答不出来也不要信口开河,面试...

嵌入式Linux 2630

骗分导论 CSP、NOIP、蓝桥杯、PAT、USACO等竞赛的算法骗分技巧 轻松省三

问题来了,那么多座桥,炸一座就破坏岛屿的联系,可能性微乎其微(除非特别设计数据)。它们的价值极大,不仅能初步帮你检验程序的对错,而且,如果你不会做这道题,你就可以直接输出样例!在OI考试中最后难的题数据最后的几个,他们往往不会创造新的数据,此时就可以直接输出最后几个数据了。需要运用《骗分导论》第3章中学到的知识,先写出朴素算法,然后造一些数据,可能就会发现规律。有些时候,问题的答案可能很有特点:对于大多数情况,答案是一样的。据说,在NOIP2013中,有人最后一题不会,愤然打了个随机数,结果得了。

星卯教育-信奥教练tony 6403

linux内存管理 (五) 9 用户空间 glibc中的内存管理

TODO

u011011827的博客 320

告别手动打卡:逍遥模拟器+宥马运动自动跑步脚本配置全流程

本文详细介绍了如何利用逍遥模拟器和自动化脚本实现宥马运动的自动跑步功能,告别手动打卡的繁琐。从环境准备、脚本部署到定位配置和智能调度,全流程指导用户完成自动化设置,提升效率并确保运动数据的真实性。

weixin_42532473的博客 539

授时中心被攻击?Windows 11 电脑时间不准?手把手教您如何更换国内稳定高速的时间服务器(时间服务器整理)

近期授时中心被攻击,时间同步重要性凸显。Windows 11 默认服务器在国内常遇网络问题。本文教你轻松修改时间服务器,选择更稳定、快速的国内优质服务器,彻底解决电脑时间不准的烦恼,让你的系统时间永远精准如一!🚀

XiaoqiangClub的博客 1082

【GLIBC 源码】 malloc内存分配

,那既然涉及到分配内存的使用,通过汇编角度的esp指针移动进行内存分配,无外乎就可同理可得,分配内存方式也可以通过指针分配,除了此方式,为了加快速度,也可推理得出可以采用mmap映射。这个32byte起到了很大的作用,因为如果你后续开辟小于132的,会先减去已经使用的,在减去32byte,得到剩余空间,来进行比较是否符合,从而进行sbrk指针的移动分配地址。这里分别写了3个malloc的内存分配,为什么数字还不一样,128不是mmap的分配阈值么?的下面,之后的代码也是同样如此,形式就如下。

学习学习学习学习 1329

YOLOv8改进 | 主干篇 | 利用MobileNetV1替换Backbone(轻量化网络结构)

本文给大家带来的改进机制是MobileNetV1,其是专为移动和嵌入式视觉应用设计的轻量化网络结构。这些模型基于简化的架构,并利用深度可分离卷积构建轻量级深度神经网络,其引入了两个简单的全局超参数,用于在延迟和准确性之间进行有效的权衡。实验表明,MobileNets在资源和准确性的权衡方面表现出色,并在多种应用(如对象检测、细粒度分类、面部属性识别和大规模地理定位)中展现了其有效性,这个模型非常适合轻量化的读者来使用。适用检测目标:轻量化网络结构适合轻量化的读者。

Snu77的博客 3966
上一篇: 超市将成为淘宝的仓库中心
下一篇: brk和sbrk及内存分配函数相关
逸学堂
博客等级 码龄23年 1104粉丝 112原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值