Glibc堆管理機制基礎

最近正在學習linux下堆的管理機制,收集了書籍和網絡上的資料,以本身的理解作了整理,作個記錄。若是有什麼不對的地方歡迎指出!python

Memory Allocator

常見的內存管理機制

  • dlmalloc:通用分配器
  • ptmalloc2:glibc分配器,繼承自dlmalloc,並提供了多線程支持,主要研究對象。
  • jemalloc:Firefox
  • tcmalloc:Chrome
  • 其餘:編程語言內存分配及回收,好比python
  • ......

malloc工做機制

第一次調用malloc

內存分配機制

頭文件:#include<unistd.h>linux

  • brk()
  1. 函數原型:int brk(void* end_data_segment)
  2. 功能和做用:用於設置program_break指向的位置。
  • sbrk()
  1. 函數原型:void* sbrk(intptr_t increment)
  2. 功能和做用:同brk(),參數能夠是負數。執行成功返回上一次program_break的值,能夠設置參數爲0返回當前的program_break.
  • mmap()
  1. 功能和做用:當用戶申請空間大於等於128kb,也就是0x20000字節時,再也不使用brk()進行分配,改成使用mmap()。
  • unmmap()
  1. 功能和做用:堆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內存管理流程圖

看不清楚能夠保存下來放大。
函數

相關文章
相關標籤/搜索