1. 什么是堆
前面的例子我们已经知道栈是什么。现在我们来介绍下堆,以及堆的实现过程。
在此之前,我们先来回顾下进程的模型
图中的:heap 部分,就是我们所说的堆,我们可以通过移动 brk
指针 来动态扩充。
或者使用 mmap 申请大的内存块。
1.1 堆在进程中的地址分布
我们可以通过查看进程消息,查看进程的地址状态
cd /proc/self
cat maps
知道了堆在进程中的位置,我们来看下堆的保存形式。
1.2 堆的申请方式
堆在进程中主要存在二个地方,一个是heap ,一个是mmap mamp 主要用于存放动态链接库。
申请方式:
堆可以通过 malloc 或者 mmap 向系统内核空间申请堆空间。
- 对于一般大小的堆的申请,使用malloc
- 对于大于128K的申请,使用 mmap。
当然这些可以通过配置项修改
1.3 堆的结构体
注 :mchunk_prev_size : 上一个chunk 的大小。 便于管理,为了后续的chunk 合并
1.3.1 已分配出去的chunk
特别注意 : 申请返回的指针,指向的 user data。
所以如果申请的是 24k,那么堆实际的空间大小 > 24k,因为它包含了头信息
1.3.2 空闲的chunk
一般会是 free 掉的,或者截取剩下的chunk
我们可以从头部中看出,这个chunk 是否来自主进程,以及它的分配方式。
fd bk 存放链表的指针,双向指针。 一个图形可以很好的解释这个情况。
2. bins
2.1 为什么使用 bins
说完了chunk ,我们紧接着谈下关联的 bins。
用户通过系统调用,申请使用内存。 使用完之后(比如free之后,程序结束之后),不会立即的返回给内核空间。(不断的切换用户态和内核态,系统消耗还是蛮大的)
所以对于heap中申请的 内存,使用完之后,不会立即释放,而是通过链表的形式保存在用户态,便于下次的再次调用。
bins 按照内存的大小,一共有128个,通过数组的形式来维护起来。
2.2 bins 的分类
我们可以从上图中,看出,bins 有
- Fast bins
- unsorted bins
- Small bins
- Large bins
small bins : 小于 512B 的chunk
large bins : 512B - 128K的 chunk
unsorted bins : 一般free 的chunk 大部分会存放到unsorted bins 里面,等待下次申请时候,再分配。 另外切割剩下的部分也会被放到 unsorted bins。 所以更多的像是一个temp ,中转站
fast bins : 相当于 bins 的缓存,采用单链表的形式,便于快速查询使用。一般都是比较小的chunk,大小是0-64B。
2.3 bins 的调用顺序
- fast bins。 针对小字节的chunk ,第一步先从 fast chunk 里面查找。 因为是单链表,且是相同大小的,速度比较快。
- small bins : 单个链表下chunk大小相同,不同链表的chunk间隔是8B。
- unsorted bins: 先查询 unsorted bins 有没有合适的,如果没有,会把 fast bins 中的bins 拿过来,用于合并和切割。 然后分配到 small bins 和 large bins。
- large bins,一个链表中大小不一样,是处于一个范围内,间隔也不相同。
- top chunk。 对于从large bins 查找不到的内存块,需要从heap 旁的chunk 去申请。可以通过移动brk 指针
- mmap chunk。 对于大于 128k,需要从mmap 中申请
100. 致敬
如有不详,请参考王老师的精彩讲解 堆栈管理
学习过程中,获得了极大的满足感,把之前的一些东西串联了起来。十分感谢 王利涛老师。
在此表示感谢。
PS:本文中所有的资源和图片均来自视频中
另外十分推荐一本书 深入理解计算机系统
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。