垃圾回收機制


垃圾回收機制

  我們定義變量會申請內存空間來存放變量的值,而內存的容量是有限的,當一個變量值沒有用了(稱為垃圾),就應該將其占用的內存給回收掉。變量名是訪問到變量的唯一方式,所以當一個變量值沒有任何關聯的變量名時,我們就無法訪問到該變量了,該變量就是一個垃圾,會被python解釋的垃圾回收機制自動回收。

一、什么是垃圾回收機制

  垃圾回收機制(簡稱GC)是python解釋器自帶的一種機制,專門用來回收不可用的變量值所占用的內存空間

二、為什么要有垃圾回收機制

  程序運行過程中會申請大量的內存空間,而對於一些無用的內存空間,如果不及時清理的話,會導致內存使用完(內存溢出),導致程序崩潰,因此,內存管理是一件重要且繁雜的事情,而python解釋器自帶的垃圾回收機制把程序員從繁雜的內存管理中解放出來。

三、垃圾回收機制原理分析

  python的GC模塊主要采用了‘引用計數’來跟蹤和回收垃圾。在引用計數的基礎上,還可以通過‘標記-清除’來解決容器對象可能產生的循環引用的問題,並且通過‘分代回收’來以空間換取時間的方式進一步提高垃圾回收的效率。

1,引用計數

  引用計數就是:變量值被變量名關聯的次數

  如:

  引用計數增加

  x=10(此時,變量值10的引用次數為1)

  y=x(此時,把x的內存地址給了y,此時,變量值10 的引用計數為2)

  引用計數減少

  x=3(此時,x和10解除關系,與3建立關系,變量值10的引用計數為1)

  del y(del是解除變量名y與變量值10之間的關系,變量值10的引用計數為0),變量值10的引用計數為0,其占用的內存空間就會被回收

2,循環引用

  引用計數機制執行效率問題:變量值被關聯次數的增加或減少,都會引發引用計數機制的執行,這明顯存在效率問題,這就是引用計數的一個軟肋,但引用計數還存在一個致命弱點,即循環引用(也稱交叉引用)。

[復制代碼](javascript:void(0)😉

# 變量名l1指向列表1,變量名l2指向列表2,如下
>>> l1=['列表1中的第一個元素']  # 列表1被引用一次   
>>> l2=['列表2中的第一個元素']  # 列表2被引用一次 
>>> l1.append(l2)             # 把列表2追加到l1中作為第二個元素,列表2的引用計數為2
>>> l2.append(l1)             # 把列表1追加到l2中作為第二個元素,列表1的引用計數為2
# l1與l2
del l1     #列表1的引用計數為1del l2     #列表2的引用計數為1

  現在列表1和列表2都沒被其他變量名關聯,但引用計數不為0,所以不會被回收,這就是循環引用的危害,為解決這問題,python引進了‘標記-清除’,‘分代回收’。

3,標記-清除

  容器對象(list,set,dict,class,instance)都可以包含其他對象的引用,所以都可能產生循環引用。在了解‘標記-清除’之前,先得知道一個知識點:內存中有兩塊區域:堆區與棧區,在定義變量時,變量名放在棧區,變量值放在堆區,內存管理是對堆區的管理。

img

  當有效內存空間被耗盡的時候,就會停止整個程序,然后進行兩項工作,第一是標記,第二是清除

  標記:遍歷所有的GC Roots對象(棧區中的所有內容或者線程都可以作為GC Roots對象),然后將所有GC Roots對象可以直接訪問或間接訪問的對象標記為存活對象。

  清除:遍歷堆區中所有的對象,將沒有標記的對象全部清除

4,分代回收

  基於引用計數的回收機制,每次回收內存,需要把所有的對象的引用計數都遍歷一遍,這是非常耗費時間的,於是引入分代回收提高回收效率,采用‘空間換取時間的策略’。

  分代:在多次掃描的情況下,都沒有被回收的變量值,GC機制會認為,該變量值的級別會增高,對其掃描的頻率會降低。

  分代指的是根據存活時間來划分變量值的等級(也就是不同的代)

  新定義的變量值,會放在新生代中,假設每隔1分鍾掃描一次,如果發現變量值依然存活,那該變量值的等級會提高,當權重大於3(假設為3),會放到青春代中,每隔5分鍾掃描一次,繼續存活下去,權重繼續增高,當權重大於10(假設為10),會被放到老年代中,次時每隔10分鍾掃描一次,以此類推。等級越高,被垃圾回收掃描的頻率越低。

  回收:依然是引用計數作為回收依據


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM