glibc内存管理那些事儿

本文探讨了glibc内存管理的细节,包括内存分配回收策略、内存碎片问题、内存池设计以及多线程下的锁竞争。介绍了如何通过内存池减少系统调用,以及在不同内存需求下采用的最佳适应伙伴算法。同时,分析了释放内存时的合并策略和内存碎片的产生。文章还提到了在多线程环境下,如何通过锁避免竞态条件,但同时也可能导致更多的内存碎片。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux内存空间简介

Linux提供了如下几个系统调用,用于内存分配:

brk()/sbrk() // 通过移动Heap堆顶指针brk,达到增加内存目的
mmap()/munmap() // 通过文件影射的方式,把文件映射到mmap区

这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。

那么,既然brkmmap提供了内存分配的功能,直接使用brkmmap进行内存管理不是更简单吗,为什么需要glibc呢?

我们知道,系统调用本身会产生软中断,导致程序从用户态陷入内核态,比较消耗资源。
试想,如果频繁分配回收小块内存区,那么将有很大的性能耗费在系统调用中。
因此,为了减少系统调用带来的性能损耗,glibc采用了内存池的设计,增加了一个代理层,每次内存分配,都优先从内存池中寻找,如果内存池中无法提供,再向操作系统申请。

一切计算机的问题都可以通过加层的方式解决。

glibc的内存分配回收策略

glibcmalloc内存分配逻辑如下是:
在这里插入图片描述
malloc

  • 分配内存 < DEFAULT_MMAP_THRESHOLD,走__brk,从内存池获取,失败的话走brk系统调用
  • 分配内存 > DEFAULT_MMAP_THRESHOLD,走__mmap,直接调用mmap系统调用

其中,DEFAULT_MMAP_THRESHOLD默认为128k,可通过mallopt进行设置。
重点看下小块内存(size < DEFAULT_MMAP_THRESHOLD)的分配,glibc使用的内存池如下图示:
在这里插入图片描述
内存池

内存池保存在bins这个长128的数组中,每个元素都是一双向个链表。其中:

  • bins[0]目前没有使用
  • bins[1]的链表称为unsorted_list,用于维护free释放的chunk
  • bins[2,63)的区间称为small_bins,用于维护<512字节的内存块,其中每个元素对应的链表中的chunk大小相同,均为index*8
  • bins[64,127)称为large_bins,用于维护>512字节的内存块,每个元素对应的链表中的chunk大小不同,index越大,链表中chunk的内存大小相差越大,例如:下标为64chunk大小介于[512,512+64),下标为95chunk大小介于[2k+1,2k+512)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值