Python 內存管理

 

 

內存原理

內存池機制

  Python中有分爲大內存和小內存:(256K爲界限分大小內存)

1、大內存使用malloc進行分配

2、小內存使用內存池進行分配

3、Python的內存池(金字塔)

  第3層:最上層,用戶對Python對象的直接操作

  第1層和第2層:內存池,有Python的接口函數PyMem_Malloc實現-----若請求分配的內存在1~256字節之間就使用內存池管理系統進行分配,調用malloc函數分配內存,但是每次只會分配一塊大小爲256K的大塊內存,不會調用free函數釋放內存,將該內存塊留在內存池中以便下次使用。

  第0層:大內存-----若請求分配的內存大於256K,malloc函數分配內存,free函數釋放內存。

  第-1,-2層:操作系統進行操作

 

 

在 C 中如果頻繁的調用 malloc 與 free 時,是會產生性能問題的.再加上頻繁的分配與釋放小塊的內存會產生內存碎片. Python 在這裏主要乾的工作有:

  如果請求分配的內存在1~256字節之間就使用自己的內存管理系統,否則直接使用 malloc.

  這裏還是會調用 malloc 分配內存,但每次會分配一塊大小爲256k的大塊內存.

  經由內存池登記的內存到最後還是會回收到內存池,並不會調用 C 的 free 釋放掉.以便下次使用.對於簡單的Python對象,例如數值、字符串,元組(tuple不允許被更改)採用的是複製的方式(深拷貝?),也就是說當將另一個變量B賦值給變量A時,雖然A和B的內存空間仍然相同,但當A的值發生變化時,會重新給A分配空間,A和B的地址變得不再相同

對於像字典(dict),列表(List)等,改變一個就會引起另一個的改變,也稱之爲淺拷貝

 

 

 

 

內存回收

當Python中的對象越來越多,它們將佔據越來越大的內存。不過你不用太擔心Python的體形,它會乖巧的在適當的時候“減肥”,啓動垃圾回收(garbage collection),將沒用的對象清除。

從基本原理上,當Python的某個對象的引用計數降爲0時,說明沒有任何引用指向該對象,該對象就成爲要被回收的垃圾了。比如某個新建對象,它被分配給某個引用,對象的引用計數變爲1。如果引用被刪除,對象的引用計數爲0,那麼該對象就可以被垃圾回收。

Python同時採用了分代(generation)回收的策略。這一策略的基本假設是,存活時間越久的對象,越不可能在後面的程序中變成垃圾。我們的程序往往會產生大量的對象,許多對象很快產生和消失,但也有一些對象長期被使用。出於信任和效率,對於這樣一些“長壽”對象,我們相信它們的用處,所以減少在垃圾回收中掃描它們的頻率。

Python將所有的對象分爲0,1,2三代。所有的新建對象都是0代對象。當某一代對象經歷過垃圾回收,依然存活,那麼它就被歸入下一代對象。垃圾回收啓動時,一定會掃描所有的0代對象。如果0代經過一定次數垃圾回收,那麼就啓動對0代和1代的掃描清理。當1代也經歷了一定次數的垃圾回收後,那麼會啓動對0,1,2,即對所有對象進行掃描。

這兩個次數即上面get_threshold()返回的(700, 10, 10)返回的兩個10。也就是說,每10次0代垃圾回收,會配合1次1代的垃圾回收;而每10次1代的垃圾回收,纔會有1次的2代垃圾回收。

引用環的存在會給上面的垃圾回收機制帶來很大的困難。

爲了回收這樣的引用環,Python複製每個對象的引用計數,可以記爲gc_ref。假設,每個對象i,該計數爲gc_ref_i。Python會遍歷所有的對象i。對於每個對象i引用的對象j,將相應的gc_ref_j減1。

在結束遍歷後,gc_ref不爲0的對象,和這些對象引用的對象,以及繼續更下游引用的對象,需要被保留。而其它的對象則被垃圾回收。

值得注意的是

1、垃圾回收時,Python不能進行其它的任務,頻繁的垃圾回收將大大降低Python的工作效率;

  2、Python只會在特定條件下,自動啓動垃圾回收(垃圾對象少就沒必要回收)

  3、當Python運行時,會記錄其中分配對象(object allocation)和取消分配對象(object deallocation)的次數。當兩者的差值高於某個閾值時,垃圾回收纔會啓動。

 

 

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