Linux堆内存管理

个人的学习笔记, 推荐阅读

http://wooyun.jozxing.cc/static/drops/tips-14465.html

http://wooyun.jozxing.cc/static/drops/tips-16063.html

https://github.com/wizardforcel/sploitfun-linux-x86-exp-tut-zh/blob/master/understanding-glibc-malloc.md

http://www.jianshu.com/p/aad2b27992eb

首先是虚拟地址空间分布, Linux默认将高地址的1GB空间分配给内核, win默认下将高地址的2GB分配给内核, 但是也可以人为配置成1GB, 地址从上到下分别被分配给内核, 栈, 堆, BSS段, DATA段以及TEXT段

各大平台的堆内存管理机制:

  • dlmalloc – General purpose allocator
  • ptmalloc2 – glibc
  • jemalloc – FreeBSD and Firefox
  • tcmalloc – Google
  • libumem – Solaris

linux下malloc本质上都是通过系统调用brk和mmap实现的

brk():

该函数申请堆的方式是:设置进程的数据段的结束地址,即可以扩大或者是缩小数据段(Linux下数据段和BSS段合称数据段)。如果我们将数据段的结束地址向高地质移动(数据段变小),那么扩大的那部分空间常常用来作为堆空间。

mmap():

该函数的作用是向操作系统申请一段虚拟空间,这块虚拟地址空间可以映射到某个文件,当它不进行映射的时候,我么又称这块空间为匿名空间,匿名空间就可以用来作为堆空间。

主线程申请malloc之后:

产生132KB大小的堆, 称为arena, 被分配给主线程的arena称为main arena , arena中有许多chunk, 以链表的形式组织, 当之后再申请malloc, 会优先从main arena中分配

主线程调用free后:

已经申请的堆空间没有返回给系统, 而是交由glibc管理, 把这段free掉的区域添加在了「main arenas bin」中(在「glibc malloc」中,空闲列表数据结构被称为「bin」)此后再申请堆空间时, 优先从bin中寻找

子线程malloc之前:

没有堆空间段, 但是有每个子线程的栈段

子线程malloc后:

由mamp()分配132KB大小的连续内存段称为thread arena

子线程free后:

free掉的区域被添加到thread arenas bin

Arena

arena的数量不完全与线程数量相关, 由处理器核心数决定:

当线程数 > arena数量的时候, 如何共享:

首先,glibc malloc循环遍历所有可用的arenas,在遍历的过程中,它会尝试lock该arena。如果成功lock(该arena当前对应的线程并未使用堆内存则表示可lock),比如将main arena成功lock住,那么就将main arena返回给用户,即表示该arena被线程3共享使用。

而如果没能找到可用的arena,那么就将线程3的malloc操作阻塞,直到有可用的arena为止。

现在,如果线程3再次调用malloc的话,glibc malloc就会先尝试使用最近访问的arena(此时为main arena)。如果此时main arena可用的话,就直接使用,否则就将线程3阻塞,直到main arena再次可用为止。

堆管理

三种数据结构:

heap_info

Heap Header—— 一个「 thread arena 」可以有多个堆。每个堆都有自己的堆 Header。为什么需要多个堆? 每个「 thread arena 」都只包含一个堆,但是当这个堆段空间耗尽时,新的堆(非连续区域)就会被 mmap 到这个 「aerna」

malloc_state

Arena header—— 一个 「thread arena 」可以有多个堆,但是所有这些堆只存在 「arena」 header 。「arena header 」包括的信息有:「bins」、「top chunk」、「last remainder chunk」

malloc_chunk

Chunk header—— 一个堆根据用户请求被分为若干「chunk」。每个这样的「chunk」都有自己的「chunk」 header。

chunk

  • Allocated chunk
  • Free chunk
  • Top chunk
  • Last Remainder chunk

从本质上来说,所有类型的chunk都是内存中一块连续的区域,只是通过该区域中特定位置的某些标识符加以区分。

Bins

空闲列表数据结构, 用于保存空闲的chunk

  • Fast bin
  • Unsorted bin
  • Small bin
  • Large bin

fastbinsY: 这是一个数组,用于记录所有的fast bins;
bins: 这也是一个数组,用于记录除fast bins之外的所有bins。事实上,一共有126个bins,分别是:
bin 1 为unsorted bin;
bin 2 到63为small bin;
bin 64到126为large bin。

fast bin

用于保存fast chunk, fast chunk是大小为16-80字节的chunk