Python原始碼閱讀-記憶體管理機制(一)

wklken發表於2015-12-04
========================== 

基本閱讀完了, 只是沒時間梳理, 趁著這今天時間比較空

逐步梳理, 發上來……也算是小結下, 要開始準備簡歷找工作了>_

這篇略長, 帶很多圖, 所以一分為二


Python的記憶體管理架構

基本分層

Objects/obmalloc.c原始碼中, 給了一個分層劃分

可以看到

第三層layer 3前面已經介紹過了, 幾乎每種常用的資料型別都伴有一套緩衝池機制.

在這裡, 我們關注的是layer 2/1

簡要介紹下layer 1, 然後重點關注layer 2, 這才是重點

layer 1: PyMem_ API

PyMem_ API是對作業系統記憶體管理介面進行的封裝

檢視pymem.h可以看到

然後object.c中, 我們關注實現, 三個實現的函式呼叫了對應的巨集

這些介面都相對簡單

好了, 結束, 開始關注layer 2: Python's object allocator


Python 的記憶體分配策略

先來看Objects/obmalloc.c中的一段註釋

Python引入了記憶體池機制, 用於管理對小塊記憶體的申請和釋放

邏輯

整個小塊記憶體池可以視為一個層次結構

block

Python記憶體的最小單位, 所有block長度都是8位元組對齊的

注意這裡block只是一個概念, 在原始碼中並沒有實體存在.

不同型別block, 對應不同記憶體大小, 這個記憶體大小的值被稱為size class.

不同長度的block

例如

圖示:

注意: 這裡有個Size class idx, 這個主要為了後面pool中用到

size classsize class index之間的轉換

pool

pool管理block, 一個pool管理著一堆有固定大小的記憶體塊

本質: pool管理著一大塊記憶體, 它有一定的策略, 將這塊大的記憶體劃分為多個大小一致的小塊記憶體.

pool size

在Python中, 一個pool的大小通常為一個系統記憶體頁. 4kB

pool組成

pool的4kB記憶體 = pool_header + block集合(N多大小一樣的block)

pool_header

pool_header的作用

結構圖:

pool初始化

從記憶體中初始化一個全新的空的pool

Objects/obmalloc.c

初始化後的圖

pool進行block分配 – 0 總體程式碼

總體分配的程式碼如下

pool進行block分配 – 1 剛開始

記憶體塊尚未分配完, 且此時不存在回收的block, 全新進來的時候, 分配第一塊block

所以進入的邏輯是程式碼-2

結果圖示

pool進行block分配 – 2 回收了某幾個block

回收涉及的程式碼

沒釋放一個block, 該block就會變成 pool->freeblock 的頭節點, 而單連結串列一個節點如何指向下一個節點呢? 通過賦值, 節點記憶體空間儲存著下個節點的地址, 最後一個節點指向NULL(知道上面程式碼-1的判斷條件了吧>_

假設已經連續分配了5塊, 第1塊和第4塊被釋放

此時記憶體圖示

此時再一個block分配呼叫進來, 執行分配, 進入的邏輯是程式碼-1

pool進行block分配 – 3 pool用完了

pool中記憶體空間都用完了, 進入程式碼-3

獲取下一個pool(連結串列上每個pool的block size都是一致的)

好了, pool到此位置, 下篇進入arena

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

Python原始碼閱讀-記憶體管理機制(一) Python原始碼閱讀-記憶體管理機制(一)

相關文章