1. 什么是堆

前面的例子我们已经知道栈是什么。现在我们来介绍下堆,以及堆的实现过程。

在此之前,我们先来回顾下进程的模型

clipboard.png

图中的:heap 部分,就是我们所说的堆,我们可以通过移动 brk 指针 来动态扩充。
或者使用 mmap 申请大的内存块。

1.1 堆在进程中的地址分布

我们可以通过查看进程消息,查看进程的地址状态

cd /proc/self
cat maps

clipboard.png

clipboard.png

知道了堆在进程中的位置,我们来看下堆的保存形式。

1.2 堆的申请方式

堆在进程中主要存在二个地方,一个是heap ,一个是mmap mamp 主要用于存放动态链接库。

申请方式:
堆可以通过 malloc 或者 mmap 向系统内核空间申请堆空间。

  • 对于一般大小的堆的申请,使用malloc
  • 对于大于128K的申请,使用 mmap。
当然这些可以通过配置项修改

1.3 堆的结构体

clipboard.png

注 :mchunk_prev_size : 上一个chunk 的大小。 便于管理,为了后续的chunk 合并

1.3.1 已分配出去的chunk

clipboard.png

特别注意 : 申请返回的指针,指向的 user data。
所以如果申请的是 24k,那么堆实际的空间大小 > 24k,因为它包含了头信息

1.3.2 空闲的chunk

一般会是 free 掉的,或者截取剩下的chunk

clipboard.png

我们可以从头部中看出,这个chunk 是否来自主进程,以及它的分配方式。

fd bk 存放链表的指针,双向指针。 一个图形可以很好的解释这个情况。

clipboard.png

2. bins

2.1 为什么使用 bins

说完了chunk ,我们紧接着谈下关联的 bins。

用户通过系统调用,申请使用内存。 使用完之后(比如free之后,程序结束之后),不会立即的返回给内核空间。(不断的切换用户态和内核态,系统消耗还是蛮大的)

所以对于heap中申请的 内存,使用完之后,不会立即释放,而是通过链表的形式保存在用户态,便于下次的再次调用。

clipboard.png

bins 按照内存的大小,一共有128个,通过数组的形式来维护起来。

clipboard.png

2.2 bins 的分类

我们可以从上图中,看出,bins 有

  1. Fast bins
  2. unsorted bins
  3. Small bins
  4. 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 的调用顺序

  1. fast bins。 针对小字节的chunk ,第一步先从 fast chunk 里面查找。 因为是单链表,且是相同大小的,速度比较快。
  2. small bins : 单个链表下chunk大小相同,不同链表的chunk间隔是8B。
  3. unsorted bins: 先查询 unsorted bins 有没有合适的,如果没有,会把 fast bins 中的bins 拿过来,用于合并和切割。 然后分配到 small bins 和 large bins。
  4. large bins,一个链表中大小不一样,是处于一个范围内,间隔也不相同。
  5. top chunk。 对于从large bins 查找不到的内存块,需要从heap 旁的chunk 去申请。可以通过移动brk 指针
  6. mmap chunk。 对于大于 128k,需要从mmap 中申请

100. 致敬

如有不详,请参考王老师的精彩讲解 堆栈管理
学习过程中,获得了极大的满足感,把之前的一些东西串联了起来。十分感谢 王利涛老师
在此表示感谢。
PS:本文中所有的资源和图片均来自视频中
另外十分推荐一本书 深入理解计算机系统


天真真不知路漫漫
70 声望6 粉丝

1