內存管理(一) ptmalloc基礎知識

本文討論了:

1.ptmalloc的簡單概念

2.各種chunk

3.bin數組以及brkmmap

 

 

 

1.ptmalloc的簡單概念

 

    glibc在開始的時候malloc是不支持多線程的,但是在glibc_2.3x中集成了ptmalloc2,也就是平常使用的malloc。這就實現了對多線程編程的支持。本文將討論ptmalloc的整個malloc(),free()以及他的初始化等。

 

    爲了保證內存的高效分配,在第一次調用malloc函數的時候會對整個ptmalloc初始化。初始化將預先分配一塊內存,然後切割成若干塊。將大於內存分配請求的一塊內存交給當前進程(包含頭部尾部,還要有一部分來記錄)。當free的時候這塊內存也不會立刻返回給操作系統,而是放到一個bin數組下,這個數組採用鏈表的方式保存着若干內存塊,當觸發某個條件的時候,內存會合並並且修改地址到另外的元素指針下。儘量避免內存碎片。

 

對於ptmalloc,他的設計是這樣的:

    1.具有長生命週期的大內存將使用mmap分配。

    2.對於短生命週期的內存分配將使用brk系統調用。

    3.對於小內存塊的釋放將返回到bin數組下,大內存(使用mmap分配的)將直接返回給操作系統。

    4.小內存塊的合併(切割)僅僅在mallocfree的時候,並且合併(切割)以後也不一定返回給操作系統

    5.設置了若干閥值來避免內存暴增的現象。

    6.爲了支持多線程,多個線程可以從同一個分配區分配內存,但是會使用鎖來保證線程安全。同時爲了優化算法,在出現內存不夠的時候會重新創建一個分配區。

 

 

 

2.chunk

 

前面提到了bin數組是存放空閒內存塊的,內存塊的將翻譯成chunk,一個使用中的chunk是這樣的

 內存管理(一) <wbr>ptmalloc基礎知識


    chunk指針代表着chunk的頭,一個chunk包含了用戶請求的內存區域和相關的控制信息,mem指針指向的纔是真正返回給用戶的內存指針。P代表着前一個內存塊是否被使用,p0時代表前一個chunk爲空閒,此時第一個域纔有效。p1時代表前一個chunk使用中,第一個域無效。M代表着分配區,爲0時代表從heap區分配,爲1時代表從mmap分配。

    A代表着分配區,爲0時代表主分配區,爲1時代表非主分配區。

空閒時的chunk如圖。

內存管理(一) <wbr>ptmalloc基礎知識

    當chunk空閒時,M狀態不存在並且在原本用戶區的地方存儲了包含後一個空閒chunk,前一個空閒chunk的指針。同時包含了爲了加快在large bin中查找最近匹配的空閒chunk的指針(比如在large bin,這個chunk和後一個chunk大小一樣,指針將直接指向後兩個chunk的位置)。

 

chunk的空間複用

爲了讓其最大化利用當前chunk的空間,在chunk被使用的時候,第一個域是沒有用的。那麼錯過你最大化利用處理,一個使用中的chunk的大小應該是(用戶請求大小+4)並且與8對齊。

 

 

3.Bins

 

    在free內存以後,內存不會馬上歸還給系統,ptmalloc會統一管理heapmmap銀蛇區域中的空心啊chunk,當用戶進行下一次分配請求時,ptmalloc會首先在空閒的chunk挑選一塊返回,這些chunk被用一個雙向鏈表連接起來,這個鏈表叫binptmalloc維護了128bin並用一個數組來存儲(通俗的說法就是一個128大小的數組,裏面放着指向雙向鏈表的頭結點的指針,每個相連bin大小差爲8B

內存管理(一) <wbr>ptmalloc基礎知識

    數組分三層,第一層是unsorted bin,第二層是small bin,第三層是large bin。最低一層是unsorted bin,這一層又分爲兩個塊 :fast binsunsortedbinfast bins 這一層放着小於64B的內存塊,當一個內存小於64B的被free後,將放入到Fast Bins.如果在接收到小於64Bmalloc請求,將首先從fast bins中查找。查找不到將進入unsorted bin中查找。

 

    fast bin的內存在某個特定的時候將合併放入第二層unsorted bin(合併時間後文會討論)。這也就避免了最小找不到就直接到最大找的情況。unsorted bin同時接受用戶釋放的chunk大於max_fast的內存塊。可以將其理解爲一個最小和最大的潤滑劑

 

 

    在bin數組無法滿足內存分配需求的時候,ptmalloc將尋找一塊大塊內存。

大塊內存又分爲以下幾種:Top chunk,mmaped chunklase remainder.接下來將討論前兩個。

 

 

Top chunk 

 

    Top chunk對於主分配區和非主分配區的分配方式是不一樣的。對於非主分配區,會預先從mmap區銀河一塊較大內存模擬sub_heap,通過管理sub_heap來響應用戶請求。因爲內存是按地址從低向高進行分配的,在空閒內存的最高處一定會存在着一塊空閒的chunk,叫做top chunk。當bins不能滿足修的時候,ptmalloc會從top chunk中挑一塊內存返回。如果top chunk自己也不夠大,那麼分配程序會從新分配一個sub_heap並且將top chunk遷移到新的sub heap上。新的sub heap將和舊的連接起來,然後在從裏面分配內存。Top chunk是永遠不會返回進bin數組的,如果chunkfree掉,那麼chunk會直接返回到sub_heap中。如果返回的chunktop相鄰,那麼這兩個chunk就會合成新的top chunk,從而使top chunk變大。如果在free的時候內存大於某個閥值,並且top chunk的大小也超過了收縮閥值,那麼ptmalloc會搜索sub_heap.如果top_chunk包含了整個sub_heap ,ptmalloc會調用munmap將整個sub_heap的內存返回給操作系統。

    對於主分配區,主分配區是唯一能夠映射到進程heap區的分配區,它可以通過sbrk來增大或者搜索進程heap的大小。ptmalloc會在開始的時候預先分配一塊較大的空閒內存(作爲初始的heap給全局),主分配區的top chunk在第一次調用malloc(超過bin數組上限)時會分配一塊(chunk_size+128Kalign4KB大小的空間作爲初始的heap(具體大小其實是可以調整的)。當返回內存的時候如果恰好和 top chunk相鄰就合併成新的top chunk。當單次回收或者top chunk超過閥值,會執行內存收縮。減小top chunk的大小。如果向主分配區的top chunk申請但是top chunk沒有足夠的內存,會執行sbrkheap的邊界上移,然後調整top chunk的大小。

 

 

 

mmaped chunk

 

    如果需要分配的chunk 足夠大,大到連bin甚至top chunk本身也不能滿足分配需求的時候,ptmalloc會使用mmap來慧姐使用內存映射來將頁映射到進程空間。這樣分配的chunk在被free的時候將直接解除映射。於是就將內存返回給操作系統。此時如果在對該內存區的引用將產生段錯誤(segmentation fault)這樣的chunk也不會包含在任何bin中。

 

 

brk修改heap區的大小,mmap映射

 

    .bss段之上分配給用戶程序的空成爲heapstart_brk指向heap的開始,而brk指向heap的頂部。可以使用系統調用brk()sbrk()來增大標識heap頂部的brk值。從而增大heap空間。在使用malloc之前,brk的值等於start_brk,即heap大小爲0,ptmalloc開始的時候如果請求的空間小於mmap分配閥值(默認128K)主分配區會調用sbrk增加一塊大小爲(128K+chunk_size)lign4K 的空間作爲heap.非主分配區會調用mmap映射一塊大小爲HEAP_MAX_SIZE(32位系統默認是1M64位默認是64M)的空間作爲sub_heap。這就是ptmalloc所維護的分配空間。

    當用戶的請求超過mmap分配閥值,並且主分配區調用sbrk失敗,或者是非主分配區在top chunk中不能分配到需要的內存,ptmalloc會嘗試調用mmap直接映射一塊內存到進程內存空間,使用mmap直接映射的chunk在釋放的時候會直接解除映射。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章