有關於ptmalloc的一些總結
在glibc下的ptmalloc的一點點分析。數組
關於chunk組織
![圖片描述 圖片描述](http://static.javashuo.com/static/loading.gif)
- chunk指針指向一個chunk的開始處,而mem指針纔是真正分配給用戶的儲存空間。
- chunk的第二個域的最低一位P表示前一個chunk是不是在使用當中(0表明前一個空閒,1表明在使用當中)。
當P爲0時,此時prev_size纔有效,第一個域表示的是前一個chunk的size,能夠經過這個值取到前一個chunk的開始地址;當P爲1時,表示前一個chunk在使用當中,prev_size無效。
ptmalloc分配的第一個chunk老是將P設爲1,以防止程序引用到不存在的區域。
- chunk第二個域倒數第二位M(0表示是從mmap映射區域分配的,1表示heap區域分配)
- chunk第二個域倒數第三位A(1表示主分配區,0非主分配區)
- 當chunk空閒時,user_data區域儲存了4個指針。
指針fd指向後一個空閒的chunk;
指針bk指向前一個空閒的chunk;
fd_nextsize以及bk_nextsize兩個指針用於加快在large bin中查找最近匹配的空閒chunk
- chunk利用標誌來管理使用和空閒的內存,減小了內存歸還所帶來的系統消耗,而且在一個未使用的chunk中,它的prev_size部分是能夠被緊挨的上一個使用的chunk空間複用的。
關於bins
用戶free掉的內存並非直接就歸還給系統,ptmalloc會統一管理heap和mmap映射區域中的空閒chunk,當用戶有分配請求時候,ptmalloc會首先在空閒的chunk中挑選一塊符合需求的交給用戶,這樣避免了頻繁的系統調用,下降了內存分配的開銷。函數
- ptmalloc將類似大小的chunk用雙向鏈表連接起來,這樣的一個鏈表就被叫作bin,ptmalloc一共維護了128個bin,並用一個數組來儲存這些bin
- 數組第一個是unsorted bin,ptmalloc在合併空閒的chunk時會放入,若是用戶釋放的chunk大於max_fast或者fast bins中空閒的chunk合併以後都會放入unsorted bin中。
ptmalloc在fast bins中沒有找到合適的chunk就會進入unsorted bins中查找,若是仍是沒有找到,就會把unsorted bin彙總的chunk加入到bins當中,這樣看來,unsorted bin相似於bins中的一個緩衝區。
- 數組的2到64個bin被稱爲small bins,同一個small bin中的chunk大小相同,兩個相鄰的small bin相差8字節;
- 後面64個bin稱爲large bins,這裏面的每個bin都是一個範圍內的chunk而且是按大小序排列好的;
- fast bins
- 引入它是由於在分配時可能會常常申請和釋放一些很小的空間,分配器合併以後又須要分割,這樣太太低效,故而在不大於max_fast(默認值是64B)的chunk釋放後會先被放到fast_bins中,不去改變他們的P標誌位,因此他們沒法合併,在小於等於max_fast時首先在fast_bins中查找相應的空閒塊。
- Top chunk
這是一開始所劃分出來的一個大空閒內存,若是bins以後尚未知足的chunk,那麼經過Top chunk來劃分一個新的chunk給用戶
- mmaped chunk
當top chunk都不能知足時,經過mmap將頁映射到進程空間中,這樣的chunk被free時候直接解除映射歸還給系統。
- last remainder
當所請求的chunk是一個小空間的,可是在small bins中又沒有合適的chunk,那麼從last remainder chunk中分裂出兩個chunk,一個給用戶,一個變成新的last remainder chunk。
sbrk和mmap
.bss段之上的分配給用戶程序的空間叫作堆,start_brk指向堆的開始,brk指向堆的頂部,能夠經過brk()和sbrk()來增長標識堆頂的brk的值。spa
在使用malloc以前brk等於start_brk,請求分配時如果請求空間小於mmap的分配閾值(mmap threshold,默認是128k),主分配區會調用sbrk()增長一塊大小爲4k的空間做爲heap。非主分配區則會調用mmap映射一塊HEAP_MAX_SIZE(32位系統下默認1M,64位系統下默認是64M)大小的空間做爲sub-heap。操作系統
ptmalloc分配概述
- 獲取分配區的鎖,爲了防止多個線程同時訪問同一個分配區。
- 將用戶請求的大小轉換位實際須要分配的chunk空間的大小。
- 判斷所需分配的chunk大小是否小於max_fast,若是大於則跳轉第五步。
- 首先城市在fast bins中查找一個chunk給用戶,若是存在則分配結束。
- 判斷所需大小是否處在small bins中,若是chunk大小處在small bins中,則根據所需chunk大小,找到具體所在的某個索small bin,從bin的尾部摘取一個知足大小的chunk返回給用戶。不然到第六步。
- 到了這一步說明分配的是一個大塊內存或者small bins中沒有合適的chunk。那麼首先會遍歷fast bins中的chunk與相鄰chunk合併連接到unsorted bin中,而後遍歷unsorted bin中的chunk,若是隻有一個上次分配已經使用的chunk,而且這個chunk知足small bins的要求且這個chunk符合用戶所要求的大小,那麼直接對這個chunk進行分割返回給用戶,不然將它放入small bins或者large bins中。
- 排除了fast bins和unsorted bin中的chunk,到了這一步從large bins中找到一個合適的chunk,從中劃分一塊所需大小的chunk,並將剩餘部分連接回bins中,若分配成功則結束,不然下一步。
- 若是bins中都沒有合適的chunk,那麼則對top chunk進行分割來分配給用戶,成功則結束,不然下一步。
- 到了這一步證實top chunk不能知足需求,那麼對於主分配區就調用sbrk()來增長top chunk的大小;對於非主分配區則會調用mmap來分配一個新的sub-heap增長top chunk的大小或者直接mmap()直接映射分配。
關於內存的回收
- free()函數也會先獲取分配區的鎖。
- 判空,若是是空直接return。
- 判斷所需釋放的chunk是否是mmaped chunk,如果是,直接調用munmap()釋放mmaped chunk,解除內存映射。不然下一步。
- 判斷chunk的大小和所處的位置,若是chunk_size<=max_fast,而且chunk不在堆頂,也就不與top chunk相鄰,則轉到下一步,不然轉到第六步。
- 將chunk放到fast bins中,將chunk放入到fast bins中,並不修改當前的chunk的使用標誌P,以後釋放結束從free()中返回。
- 判斷前一個chunk是否在使用當中,若是前一個塊也是空閒塊那麼進行合併。
- 判斷當前釋放的下一個塊是否是top chunk,若是是則轉到第九步,不然下一步。
- 判斷下一個chunk是否處在使用中,若是下一個chunk也是空閒的則合併後放入unsorted bin中。
- 若是執行到這一步,說明釋放了一個和top chunk相鄰的chunk。
- 判斷合併後的chunk大小是否大於FASTBIN_CONSOLDATION_THRESHOLD(默認64KB),若是是則觸發進行fast bins的合併操做。
- 判斷top chunk是否大於mmap的收縮閾值(默認128K),若是是的話,對於主分配區,則會試圖歸還top chunk中的一部分給操做系統。