from:http://blog.chinaunix.net/uid-18770639-id-3385860.html

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. int main()
  5. {
  6. int alloc_time = 4000;
  7. char *a[alloc_time];
  8. char *b[alloc_time];
  9. int i, j;
  10. for(i=0; i<alloc_time; i++)
  11. {
  12. a[i] = (char *)malloc(52722);
  13. memset(a[i], 1, 52722);
  14. b[i] = (char *)malloc(1);
  15. memset(b[i], 1, 1);
  16. }
  17. printf("malloc finished\n");
  18. for(i=alloc_time-1; i>=0; i--)
  19. {
  20. free(a[i]);
  21. free(b[i]);
  22. }
  23. printf("free finished\n");
  24. //char *p = (char *)malloc(2000);
  25. //free(p);
  26. while(1){
  27. sleep(3);
  28. }
  29. }

运行这个测试程序,发现Glibc内存暴增,程序已经把内存返回给了Glibc库,但Glibc库却没有把内存归还给操作系统。

分析:

ptmalloc使用chunk结构来实现内存管理。用户free掉的内存并不是都会马上归还给系统,ptmalloc会统一管理heap和mmap映射区域中的空闲chunk。当用户进行下一次分配请求时,ptmalloc会首先试图在空闲的chunk中挑选一块给用户,这样就避免了频繁的系统调用,降低了内存分配的开销。对于空闲的chunk,ptmalloc采用分箱式内存管理方式,根据空闲chunk的大小和处于的状态将其放在三个不同的容器中。

bins:ptmalloc将相似大小的chunk用双向链表链接起来,这样的一个链表被称为一个bin。bins有128个队列,前64个队列是定长的(small bins),每隔8个字节大小的块分配在一个队列,后面的64个队列是不定长的(largebins),就是在一个范围长度的都分配在一个队列中。所有长度小于512字节的都分配在定长的队列中,后面的64个队列是变长的队列,每个队列中的chunk都是从大到小排列的。

unsort队列(只有一个队列),它是一个cache,所有free下来的如果要进入bins队列中都要经过unsort队列,分配内存时会查看unsorted bin中是否有合适的chunk,如果找到满足条件的chunk,则直接返回给用户,否则将unsorted bin中所有chunk放入bins中。

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

如果内存块是空闲的,它会挂在其中的一个队列中,它是通过复用的方式,使用空闲chunk的第3个字和第4个字当作它的前链和后链(变长块是第5个字和第6个字)。

malloc的步骤:

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

2.        判断需求的块是否在small bins(bins的前64个bin)范围,如果在小箱子范围,并且刚好有满足需求的块,则直接返回内存地址;

3.        到了这一步,说明需要分配的是一块大内存,或者小箱子里找不到合适的chunk;这个时候,会触发consolidate,ptmalloc首先会遍历fastbins中的chunk,将相邻的chunk合并,并链接到unsorted bin中(因为在大箱子找一般都要切割,所以要优先合并,避免过多碎片);

4.        在unsort bin中取出一个chunk,如果能找到刚好和想要的chunk相同大小的chunk,立刻返回,如果不是想要的chunk大小的chunk,就把它插入到bins对应的队列中去,转到2。

5.        到了这一步,说明需要分配的是一块大的内存,或者small bins和unsorted bin中都找不到合适的chunk,并且fastbins和unsorted bin中所有的chunk都清楚干净了。在large bins中找,找到一个最小的能符合需求的chunk从队列中取下,如果剩下的大小还能建一个chunk,就把chunk分成两个部分,把剩下的chunk插入到unsort队列中取,把chunk的内存地址返回;

6.        如果搜索fastbins和bins都没有找到合适的chunk,那么就需要操作topchunk(是堆顶的一个chunk,不会放在任何一个队列里)来进行分配了。在topchunk找,如果能切出符合要求的,把剩下的一部分当作topchunk,然后返回内存地址;

7.        到了这一步说明topchunk也不能满足分配要求,就只能调用sysalloc,其实就是增长堆了,然后返回内存地址。

free的步骤:

1.        判断所需释放的chunk是否为mmapedchunk,如果是,则调用munmap释放mmaped chunk,解除内存空间映射,该空间不再有效,然后立刻返回;

2.        如果和topchunk相邻,直接和topchunk合并,不会放到其他的空闲队列中取,然后立刻返回;

3.        如果释放的大小小于max_fast(80字节),就把它挂到fastbins中去返回,使用位仍然为1,当然更不会去合并相邻块,然后立刻返回;

4.        如果释放块得大小介于80—128K,把chunk的使用位置为0,判断前一个chunk是否处于使用中,如果前一块也是空闲块,则合并,并转入下一步;

5.        判断当前释放chunk的下一个块是否为topchunk,如果是,则转到第7步,否则转下一步;

6.        判断下一个chunk是否处在使用中,如果也是空闲的,则合并,并将合并后的chunk挂到unsort队列中去;

7.        如果执行到了这一步,说明释放了一个与top chunk相邻的chunk;则无论它有多大,都将它与topchunk合并,并更新topchunk的大小等信息,转下一步;

8.        如果合并后的大小大于FASTBIN_CONSOLIDATION_THRESHOLD(64K),也会触发consolidate,即fastbins的合并操作,合并后的chunk会被放到unsortedbin中,fastbins将变为空,操作完成之后转下一步;

9.        试图收缩堆。(判断topchunk的大小是否大于mmap的收缩阈值,默认为128KB)。

ptmalloc对于大于128K的块通过mmap方式来分配,小于128K(mmap分配阈值)的块在heap中分配。堆是通过brk的方式来增加或压缩的,如果在现有的堆中不能找到合适的chunk,会通过增长堆的方式来满足分配,如果堆顶的空闲块超过一定的阈值会收缩堆,所以只要堆顶的空间没释放,堆是一直不会收缩的。因为ptmalloc的内存收缩是从top chunk开始,如果与top chunk(堆顶的一个chunk)相邻的那个chunk在内存池中没有释放,top chunk以下的空闲内存都无法返回给系统,即使这些空闲内存有几十个G也不行。

按照这个测试程序分配后,内存变成由小块和大块交替出现,释放小块的时候,直接把小块放在fastbins中取,而且他的使用位还是1,释放大块的时候,它试图合并相邻的块,但是和它相邻的块的使用位还是1,所以它不能把相邻的块合并起来,而且释放的块的大小小于64K,也不会触发consolidate,即不会把fastbins清空,所以当所有的块都被释放完后,所有的小块都在fastbins里面,使用位都还是1,大块都挂在unsort队列里面。全部都无法合并。所以使用的堆更加无法压缩。如果在循环后面再分配2000字节然后释放的话,所有内存将全部被清空,这是因为再申请2000字节的时候,由malloc的第二步,程序会先调用consolidate,即把所有的fastbins清空,同时把相邻的块合并起来,等到所有的fastbins清空的时候,所有的块也被合并起来了,然后调用free(2000)的时候,这块将被合并起来,成为topchunk,并且大小远小于64K,所有堆将会压缩,内存归还给系统。

解决方法:

减小mmap分配阈值,对于大内存块分配尽量采用mamp系统调用直接向操作系统分配,回收时用munmap返回给操作系统。但是这种做法会降低ptmalloc的分配释放效率,因为系统调用mamp是串行的,操作系统需要对mmap分配内存加锁,而且操作系统对mmap的物理页强制清0很慢。
这个可以通过修改 MALLOC_MMAP_THRESHOLD_环境变量或者调用mallopt()接口来实现。

glibc(ptmalloc)内存暴增问题解决相关推荐

  1. iOS内存暴增问题追查与使用陷阱

    iOS平台的内存使用引用计数的机制,并且引入了半自动释放机制:这种使用上的多样性,导致开发者在内存使用上非常容易出现内存泄漏和内存莫名的增长情况: 本文会介绍iOS平台的内存使用原则与使用陷阱: 深度 ...

  2. 分析 Go time.After 引起内存暴增 OOM 问题

    还没正式上班,朋友来个电话让我帮忙排查一个问题.说是用 golang 写的牛逼的调度服务出现了内存泄露问题,Go 内存在任务暴增的时候增长很诡异. 从上线部署起,只要上游任务一上量就 oom 了.大过 ...

  3. android 图库 imgcache.idx,iOS开发 - 关于列表图片渲染内存暴增问题

    关于列表图片渲染内存暴增问题 - (void)viewDidLoad { [super viewDidLoad]; [SDImageCache sharedImageCache].config.sho ...

  4. 加载大量图片内存暴增导致闪退 Terminated due to memory issue(内存暴增SDWebImage加载高清大图崩溃)

    上传图片一定要压缩,一定要压缩,一定要压缩.(目前手机拍摄的图片一张几M,上传后不压缩,如果几十张一块加载展示时内存画面有点美!如果是后台上传除了需要高清以外的图也需要压缩处理) 下载大量图片时一定要 ...

  5. BitArray虽好,但请不要滥用,又一次线上内存暴增排查

    一:背景 1. 讲故事 前天写了一篇大内存排查在园子里挺火,这是做自媒体最开心的事拉,干脆再来一篇满足大家胃口,上个月我写了一篇博客提到过使用bitmap对原来的List<CustomerID& ...

  6. iOS ☞ SDWebimage 内存暴增问题

    前言 相信很多开发都用过 SDWebimage 来解决 UITableView/UICollectionView 滑动卡顿等问题,而且很多公司在面试的时候都会被问到 SDWebimage 运行流程等问 ...

  7. 关于Services.exe开机CPU内存使用暴增解决方案

    这两天系统(Windows Server 2003 SP2)开机,发现Services.exe进程CPU使用率暴增并且伴随内存狂耗,内存和虚拟内存可以在10分钟之内耗尽.我3G内存呀,外加2G虚拟内存 ...

  8. 内存只增不减(非内存泄露)解决

    内存只增不减(非内存泄露)解决 微信公众号:幼儿园的学霸 个人的学习笔记,关于OpenCV,关于机器学习, -.问题或建议,请公众号留言; 在ADAS项目中,代码中加入了跟踪模块,使得程序的内存占用不 ...

  9. 流量暴增,掌门教育如何基于 Spring Cloud Alibaba 构建微服务体系?

    作者 | 童子龙  掌门教育基础架构部架构师 **导读:**本文整理自作者于 2020 年云原生微服务大会上的分享<掌门教育云原生落地实践>,本文主要介绍了掌门教育云原生落地实践,主要围绕 ...

最新文章

  1. cuda cudnn pytorch版本对应关系
  2. Js插入元素到数组的头部和尾部 unshift push
  3. IAR下μCosIII移植心得
  4. 软考初级信息处理技术员(一)
  5. SQL server2016 数据库 基础知识
  6. fotify php审计,Fortify下载-代码审计工具Fortify SCA下载v20.1.1 最新版-西西软件下载...
  7. 玉品游戏java_整蛊游戏N合一(玉品)
  8. AutoCAD .NET 二次开发实例(2) 批量统计指定图层线段长度
  9. 可验证随机函数(Verifiable Random Function, VRF)
  10. php遵义旅游管理系统毕业设计源码091801
  11. 如何修复DNS劫持?dns被劫持了怎么办有什么解决方法
  12. 1.5.37:雇佣兵
  13. 数据库与MPP数仓(二十三):postgreSQL集群与高级特性
  14. Linux定时任务与开机自启动脚本
  15. 5.MCScanX 与circos下载、安装、运用
  16. 锤子android 7,锤子正式加入安卓7.1.1阵容 一加3/3T尝鲜氢OS公测版
  17. !Character.isDigit(a.charAt(i))
  18. 遥感数据集Million-AID介绍及数据预处理
  19. java编写打字游戏_程序设计:简单字母打字游戏(JAVA编写)
  20. 网御星云防火墙上网行为审计配置

热门文章

  1. leetcode算法题--数组中数字出现的次数 II
  2. leetcode算法题--矩阵区域和
  3. 文件服务器传输,文件服务器传输
  4. 20162329 2017-2018-1 《程序设计与数据结构》第九周学习总结
  5. RabbitMq install on Centos
  6. 袁晖:C2B汽车电商模式创新
  7. Firebug高级用法 - Web开发的利器
  8. H3CNE考试讨论群
  9. C#中操作XML (节点添加,修改,删除完整版)
  10. php实现 三角形_PHP使用for循环输出三角形