Python源碼閱讀-內存管理機制(二)

arena

arena: 多個pool聚合的結果

arena size

pool的大小默認值位4KB

arena的大小默認值256KB, 能放置 256/4=64 個pool

obmalloc.c中代碼

arena 結構

一個完整的arena = arena_object + pool集合

arena_object的作用

pool_header 與 arena_object

arena的兩種狀態

arena存在兩種狀態: 未使用(沒有建立聯繫)/可用(建立了聯繫)

全局由兩個鏈表維護着

arena的初始化

首先, 來看下初始化相關的一些參數定義

代碼obmalloc.c

然後, 看下obmalloc.carena初始化的代碼

圖示: 初始化arenas數組, 初始化後的所有arena都在unused_arena_objects單鏈表裏面

圖示: 從arenas取一個arena進行初始化

沒有可用的arena?

此時

然後, 假設第一次分配了16個, 發現沒有arena之後, 第二次處理結果: numarenas = 32

即, 數組擴大了一倍

arena分配

new了一個全新的 arena之後,

圖示: 從全新的arena中獲取一個pool

假設arena是舊的, 怎麼分配的pool

這個arena->freepools是何方神聖?

當arena中一整塊pool被釋放的時候

也就是說, 在pool整塊被釋放的時候, 會將pool加入到arena->freepools作爲單鏈表的表頭, 然後, 在從非全新arena中分配pool時, 優先從arena->freepools裏面取, 如果取不到, 再從arena內存塊裏面獲取

圖示

一個arena滿了之後呢

很自然, 從下一個arena中獲取

注意: 這裏有個邏輯, 就是每分配一個pool, 就檢查是不是用到了最後一個, 如果是, 需要變更usable_arenas到下一個可用的節點, 如果沒有可用的, 那麼下次進行內存分配的時候, 會判定從arenas數組中取一個

arena回收

內存分配和回收最小單位是block, 當一個block被回收的時候, 可能觸發pool被回收, pool被回收, 將會觸發arena的回收機制

四種情況

具體可以看PyObject_Free的代碼

內存分配步驟

好的, 到這裏, 我們已經知道了block和pool的關係(包括pool怎麼管理block的), 以及arena和pool的關係(怎麼從arena中拉到可用的pool)

那麼, 在分析PyObject_Malloc(size_t nbytes)如何進行內存分配的時候, 我們就刨除掉這些管理代碼

關注: 如何尋找得到一塊可用的nbytes的block內存

其實代碼那麼多, 尋址得到對應的block也就這麼幾行代碼, 其他代碼都是pool沒有, 找arena, 申請arena, arena沒有, 找arenas, 最終的到一塊pool, 初始化, 返回第一個block

如果有的情況, 用現成的

從上面這個判斷邏輯來看, 內存分配其實主要操作的是pool, 跟arena並不是基本的操作單元(只是用來管理pool的)

結論: 進行內存分配和銷燬, 所有操作都是在pool上進行的

usedpools 是什麼鬼? 其實是可用pool緩衝池, 後面說

內存池

arena 內存池的大小

取決於用戶, Python提供的編譯符號, 用於決定是否控制

obmalloc.c

具體使用中, python並不直接與arenas和arena打交道, 當Python申請內存時, 最基本的操作單元並不是arena, 而是pool

問題: pool中所有block的size一樣, 但是在arena中, 每個pool的size都可能不一樣, 那麼最終這些pool是怎麼維護的? 怎麼根據大小找到需要的block所在的pool? => usedpools

pool在內存池中的三種狀態

usedpools

usedpools數組: 維護着所有處於used狀態的pool, 當申請內存的時候, 會通過usedpools尋找到一塊可用的(處於used狀態的)pool, 從中分配一個block

結構:

解開看(obmalloc.c)

爲了看懂這步的trick, 心好累>_

直接上圖

new一個pool時維護

init獲得的情況, 其實就是將剛剛從arena中獲取的pool加入到 usedpools 對應的雙向鏈表中, 然後初始化, 然後返回block

從現有pool中獲取block

從現有的pool, 其實就是 usedpools得到雙向鏈表頭部, 判斷是不是空鏈表, 不是的話代表有可用的pool, 直接從裏面獲取

相關文章
相關標籤/搜索