最近正在學習linux下堆的管理機制,收集了書籍和網路上的資料,以自己的理解做了整理,做個記錄,如果有什么不對的地方歡迎指出!
Memory Allocator
常見的記憶體管理機制
- dlmalloc:通用分配器
- ptmalloc2:glibc分配器,繼承自dlmalloc,并提供了多執行緒支持,主要研究物件,
- jemalloc:Firefox
- tcmalloc:Chrome
- 其他:編程語言記憶體分配及回收,比如python
- ......
malloc作業機制
第一次呼叫malloc

記憶體分配機制
頭檔案:#include<unistd.h>
- brk()
- 函式原型:int brk(void* end_data_segment)
- 功能和作用:用于設定program_break指向的位置,
- sbrk()
- 函式原型:void* sbrk(intptr_t increment)
- 功能和作用:同brk(),引數可以是負數,執行成功回傳上一次program_break的值,可以設定引數為0回傳當前的program_break.
- mmap()
- 功能和作用:當用戶申請空間大于等于128kb,也就是0x20000位元組時,不再使用brk()進行分配,改為使用mmap(),
- unmmap()
- 功能和作用:堆mmap()申請的空間進行回收,
記憶體分配圖

- 主執行緒的arena就是main_arena,包含start_brk和brk中間的連續記憶體,當main_arena不夠分配時,會使用brk()進行擴展,
- 子執行緒arena可以有多片連續記憶體,但是大小是固定的,不可以擴展,如果不夠用的話需要再次呼叫mmap()來分配,
第二次呼叫malloc
- 只要分配的空間不超過128kb,則不會再次向system申請空間,超過時才會呼叫brk()進行擴展,
- 即使將main_arena全部free,也不會立即把記憶體還給作業系統,此時記憶體由glib進行管理,
chunk
chunk是glibc管理記憶體的基本單元,主要分為以下幾類:
- alloced chunk:已分配正在使用中的chunk,
- free chunk:已經free的chunk,
- top chunk:可以理解為地址的最高處,還沒有分配的chunk,
- last remainder chunk:是為了提高記憶體分配的區域性,
chunk = chunk header + user data,malloc回傳給用戶的其實是user data指標,具體如下圖:

alloced chunk結構

- size:本chunk的大小,包括prev,大小為8的整數倍,32位以8位元組對齊,最小為0x10,64位以16位元組對齊,最小為0x20,其中低三位有特殊含義,分別為N、M、P
- N位:是否屬于主行程,
- M位:是否由mmap()分配,
- P位:前一堆塊占用標志,1為占用,0為空閑,
- 當P位為0時,表示前一堆塊釋放,prev表示前一堆塊的大小,當P位為1,表示前一堆塊使用,prev表示前一堆塊的資料,
- userdata為輸入的資料,
- 將下一堆塊的P位設定為1,
free chunk

- 其中fd、bk屬于鏈表指標,有特殊用途,后面會講到,
- prev_size為當前釋放塊的大小(包含chunk header)
- 下一堆塊P位通常被設定為0(fastbin除外),
top chcunk

- 該堆塊位于前兩種堆塊之后,頭部結構與alloced相似
- size:top chunk還有多少空間可以分配,
- 重要的是P位:0表示上一堆塊處于空閑,1表示上一堆塊處于使用狀態,主要用于判斷free時是否能與上一堆塊進行合并(fastbin除外),
last remainder chunk
- 在malloc時,如果有比較大的chunk可以分配,會把這個chunk分成兩部分,一部分回傳給用戶,另一部分稱為remainder,加入到 unsorted bin,last remainder會記錄最近拆分的remainder,這個remainder大小至少要為MINSIZE,否則不能拆分,
- 當下次malloc時,如果last remainder chunk夠大,則重復上一程序,
- 拆分的情況:fast bin 和 small bin 都沒有合適的chunk,同時unsorted bin有且只有一個可拆分的chunk,并且這個chunk 是last remainder,
堆空閑塊管理結構bin
當alloced chunk被釋放后,會根據大小放入bin或者合并到top chunk 中去,bin的主要作用時加快分配速度,通過鏈表方式(chunk中的fd和bk指標)進行管理,主要有以下幾種,顧名思義:
- fast bin
- unsorted bin
- small bin
- large bin
fastbinsY:這是一個bin陣列,里面有NFASTBINS個fast bin
bins:也是一個bin陣列,一共有126個bin,按順序分別是:
- bin 1 為unsorted bin
- bin 2 到 bin 63 為small bin
- bin 64 到 bin 126 為 large bin
fast bin
- 這類bin通常申請和釋放的堆塊都比較小,所以使用單鏈表結構,LIFO(后進先出)分配策略,
- 為了速度,fast bin不會進行合并,下一個chunk始終處于使用狀態,
- 在fastbinsY陣列里按照從小到大的順序排列,
- 以64位為例,fast bin結構如下(大小區間0x200x80,32位為0x100x40):

unsorted bin
- 一定大小堆塊被釋放時,在加入small bin 和large bin 之前,會首先加入此bin,可以加快分配速度,使用雙鏈表結構,FIFO(先進先出)分配策略,
- unsorted bin大小可能是不相同的,
- 由于使用雙鏈表,一個bin會占用bins的兩個元素,fd指向上一個chunk,bk指向下一個,
- 以64位為例,unsorted bin結構如下(非連續記憶體,大小無限制):

small bin
- 同一個small bin里的chunk大小相同,使用雙鏈表結構,FIFO(先進先出)分配策略,
- 由于fast bin和small bin 有重合部分,在某些情況下會加入到small bin
- 根據大小分成62個不同的bin,0x20,0x30,0x40...0x80,0x90...1008
- 以64位為例,small bin結構如下(大小區間:size<0x400byte):

large bin
- 使用雙鏈表結構,FIFO(先進先出)分配策略,
- free時bk后面多兩個此引數:fd_nextsize、bk_nextsize,分別指向前一個和后一個large chunk,
- 根據大小分成63個不同的bin,大小不再固定,前32個bin為 0x400+64i,32-48 bin為 0x1380+512j,依此類推,并且會將大的chunk放在前面,小的放在后面,以加快速度,
- 以64位為例,large bin大小區間:size>=1024byte,32位為:size>=512byte,
- fd_nextsize和bk_nextsize指標用于指向第一個與自己大小不同的chunk,所以也只有在加入了大小不同的chunk時,這兩個指標才會被修改,
隨后附上glibc記憶體管理流程圖
看不清楚可以保存下來放大,

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/263613.html
標籤:Linux
