原文:http://www.cnblogs.com/gaoxing/p/4253833.html
內存分配是面向虛擬內存的而言的,以頁為單位進行管理的,頁的大小一般為4kb,當在堆里創建一個對象時(小於4kb),會分配一個頁,當再次創建一個對象時會判斷該頁剩余大小是否夠,夠的話使用該頁剩余的內存,減少系統調用。真實的內存分配算法比這個復雜了,效率不好的內存算法會導致出現很多內存碎片。
內存分配的核心思想概括起來有3條
1:首先講內存區(memory pool)以最小單位(chunk)定義出來 ,然后區分對象大小分別管理內存,小內存定義不同的規格(bins),根據不同的bin分配固定大小的內存塊,並用一個表
管理起來,大對象則以頁為單位進行管理,配合小對象所在的頁,降低碎片,設計一個好的存儲方案(metadata)減少對內存的占用,同時優化內存信息的存儲。以使對每個bin或大內存區域的訪問性能最優且有上限。
2:當釋放內存時,要能夠合並小內存為大內存,該保留的保留下次可快速響應,不該保留的釋放給系統
3:多線程環境下,每個線程可以獨立的占有一段內存區間(TLS),這樣線程內操作可以不加鎖
jemalloc是freebsd的內存分配算法,他的layout如下:
1:arena:把內存分成許多不同的小塊來分而治之,該小塊便是arena,讓我們想象一下,給幾個小朋友一張大圖紙,讓他們隨意地畫點。結果可想而知,他們肯定相互顧忌對方而不敢肆意地畫(synchronization),從而影響畫圖效率。但是如果老師事先在大圖紙上划分好每個人的區域,小朋友們就可以又快又准地在各自地領域上畫圖。這樣的概念就是arena。它是jemalloc的核心分配管理區域,對於多核系統,會默認分配4*cores個arena 。線程采用輪詢的方式來選擇響應的arena進行內存分配。
2: chunk。具體進行內存分配的區域,默認大小是4M,chunk以page為單位進行管理,每個chunk的前6個page用於存儲后面page的狀態,比如是否分配或已經分配
3:bin:用來管理各個不同大小單元的分配,比如最小的Bin管理的是8字節的分配,每個Bin管理的大小都不一樣,依次遞增。
4:run:每個bin在實際上是通過對它對應的正在運行的Run進行操作來進行分配的,一個run實際上就是chunk里的一塊區域,大小是page的整數倍,具體由實際的bin來決定,比如8字節的bin對應的run就只有1個page,可以從里面選取一個8字節的塊進行分配。在run的最開頭會存儲着這個run的信息,比如還有多少個塊可供分配。
5:tcache。線程對應的私有緩存空間,默認是使用的。因此在分配內存時首先從tcache中找,miss的情況下才會進入一般的分配流程。
arena和bin的關系:每個arena有個bin數組,每個bin管理不同大小的內存(run通過它的配置去獲取相應大小的內存),每個tcahe有一個對應的arena,它本身也有一個bin數組(稱為tbin),前面的部分與arena的bin數組是對應的,但它長度更大一些,因為它會緩存一些更大的塊;而且它也沒有對應的run的概念
chunk與run的關系:chunk默認是4M,而run是在chunk中進行實際分配的操作對象,每次有新的分配請求時一旦tcache無法滿足要求,就要通過run進行操作,如果沒有對應的run存在就要新建一個,哪怕只分配一個塊,比如只申請一個8字節的塊,也會生成一個大小為一個page(默認4K)的run;再申請一個16字節的塊,又會生成一個大小為4096字節的run。run的具體大小由它對應的bin決定,但一定是page的整數倍。因此實際上每個chunk就被分成了一個個的run。
內存分配的,具體流程如下: