python原始碼剖析 2 6章

2021-07-28 22:31:55 字數 3419 閱讀 3233

python中所有的內建物件,幾乎都會有自己的物件池機制,以避免常用物件頻繁的malloc和free

python中的int其實就是c中的long

pyintobject物件的建立:
python為建立乙個pyintobject提供了三個方法

pyint_fromlong,pyint_fromstring,pyint_fromunicode

實際上,pyint_fromstring,pyint_fromunicode是先把string或者unicode轉換成long或者float,然後呼叫pyint_fromlong或者pyint_fromfloat

小整數物件
intobject.c中small_ints定義了小整數物件的範圍,小整數會在python啟動的時候維護到block_list中,直到python關閉的時候才銷毀
大整數物件-時間與空間的兩難選擇
我們不能保證大整數就不會被經常使用,也不能將大整數都快取起來,那樣太浪費空間,python該怎麼做?

結構pyintblock中維護了一塊記憶體(block),記憶體中儲存了一定數量的pyintobject物件(一般是82個,可以調整)。

單向列表block_list維護pyintblock,每乙個block都維護了乙個pyintobject陣列--objects,陣列中儲存著真正的pyintobject物件。

全部block的objects中的所有空閒記憶體由乙個單向鍊錶來維護,這個鍊錶的表頭是free_list

當需要返回乙個大整數物件時,就需要在block的objects中尋找一塊可用於儲存新的pyintobject物件的記憶體,這個重任是free_list完成。

首次呼叫pyint_fromlong時,free_list必定為null,這時python會呼叫fill_free_list建立新的block,從而建立新的空閒記憶體,需要注意的是,每當空閒記憶體耗盡的時候,free_list都會指向null,從而在下一次pyint_fromlong的時候,呼叫fill_free_list

當物件被銷毀時(即引用計數變為0時),python會把這個物件所在的記憶體位址維護到free_list這個單向鍊錶中,以供其他物件使用

需要注意的一點是,python銷毀乙個整數物件,是把這個物件所在的記憶體維護到free_list中去,並不是還給系統,即一旦系統堆中的某塊記憶體被申請用於整數物件,那麼這塊內存在python結束之前是不會被釋放的,這一漏洞有可能將系統記憶體全部吃光

本章要研究的字串屬於變長物件中的不可變物件。字串作為不可變物件使得它可以作為dict的鍵值,但也使得一些字串操作,比如多個字串連線,的效率大大降低了。

python中,pystringobject是對字串物件的實現,pystringobject中ob_shash變數的作用是快取該物件的hash值,如果該物件還沒有計算過hash值,那麼ob_shash的初始值是-1。

intert機制的目的是:對被intert之後的字串,在整個python執行期間,只有乙個pystringobject物件與之對應(即對於相同的字串,不再單獨的分配空間),這樣既節省了空間,又簡化了字串比較

intert機制的核心在於interned,interned實際上指向乙個dict的集合,這個集合中記錄著已經被intern的字串物件,當新建乙個pystringobject物件時,會去檢查dict集合中有沒有相同的物件,如果有的話,將指向新建物件的指標指向dict集合,而新建物件的引用計數-1

python中通過+號連線字串效率是極其低下的,根源在於pystringobject是乙個不可變物件,當進行字串連線時,就必須建立乙個新的物件,如果要連線n個字串,就要進行n-1次記憶體申請及搬運工作

推薦使用join對儲存在list或tuple中的字串進行連線,這種做法只需要進行一次的記憶體分配

pylistobject物件的建立

1. pylist_new建立pylistobject物件並指定該列表初始元素個數(檢查緩衝池(free_lists)中是否有可用物件,若有,直接用)  

2. 檢查元素實際占用的空間是否過大(第一步只是指定了元素個數,並沒有計算元素實際占用空間)

3. 若緩衝池沒有可用物件,則申請記憶體

4. 在申請的記憶體中建立pylistobjects*列表,列表裡的每一項元素會被初始化為null

5. 開始維護ob_size和allocated

插入操作

1. 型別檢查,記憶體是否足夠等

2. 當newsize < allcated/2 時,python會收縮列表記憶體空間

3. 在確定插入位置之後,python會將插入點之後的所有元素後移乙個位置,這樣就能在插入點空出乙個位置了(如果是鍊錶的話,只需要修改指標就可以了,不需要移動元素,所以猜測python的list是陣列結構)

刪除操作:python的list中replace和remove呼叫的是乙個方法,當傳入的引數是null時,就是刪除,否則是替換

pylistobject物件緩衝池

1. 建立乙個新的list時,其實是分為兩步:先建立pylistobject物件,再建立這個物件維護的元素列表。銷毀過程也是一樣分為兩步:先銷毀元素列表,再銷毀pylistobject物件  

2. 在銷毀pylistobject物件本身時,會檢查free_lists緩衝池是否滿了,如果沒滿,就會把這個物件加入到緩衝池當中。注意加入緩衝池的只是pylistobject物件本身,並不包括它維護的元素列表

unused:entry的me_key和me_value都是null且這個entry之前也沒有儲存過任何值,即初始化狀態

active:entry中儲存了鍵值對時,進入這個狀態

dummy:entry中儲存的鍵值對被刪除後,轉為dummy狀態。不能轉為unused狀態,這會導致衝突探測鏈的中斷

1. python提供了兩種dict搜尋策略:lookdict和lookdict_string。lookdict_string是lookdict的特殊形式,也是預設的搜尋策略,因為用string作為key是主流

2. 當搜尋成功時,返回entry;當搜尋不成功時,返回的是乙個能提示失敗並可用的entry

3. 按key搜尋,key相同包含兩層含義:引用相同和值相同。檢查key相同時,先檢查hash值是否相同(hash值不同則其值一定不同),再檢查引用是否相同,再檢查值是否相同

4. 當待搜尋的key是pystringobject物件時,就會呼叫lookdict_string

python原始碼剖析 0 1章

python總體架構python整體架構主要可以分為三部分 1.模組 內建模組,庫,使用者自定義模組 2.python執行時環境,包括物件 型別系統 list,dict,使用者自定義物件等 記憶體分配器 建立物件時對記憶體的申請 和執行時狀態資訊 直譯器的狀態,比如正常,異常等 3.直譯器 詞法分析...

python原始碼剖析 Python原始碼剖析

第頁共 頁python 原始碼剖析 物件機制 1.物件 在python 的世界中,一切都是物件,乙個整數是乙個物件,乙個字串也是 乙個物件,更為奇妙的是,型別也是乙個物件,整數型別是乙個物件,字串類 型也是乙個物件。從 年guido 在那個聖誕節揭開 python 世界的大幕開始,一直到現在,pyt...

原始碼剖析 Hashtable 原始碼剖析

hashtable同樣是基於雜湊表實現的,同樣每個元素都是key value對,其內部也是通過單鏈表解決衝突問題,容量不足 超過了閾值 時,同樣會自動增長。hashtable也是jdk1.0引入的類,是執行緒安全的,能用於多執行緒環境中。hashtable同樣實現了serializable介面,它支...