python垃圾回收 采用方式_python-面向对象-10-__del__析构方法/垃圾回收机制
Python語言自帶垃圾回收機制,為了能夠比較清楚說明白Python的垃圾回收機制的原理,我們今天就從最底層的解釋器開始,采用由內到外的方式來說明。
1.Python默認解釋器CPython
Python語言擁有多種解釋器,但是默認采用CPython實現。CPython實際上是用C語言編寫的。主要功能如下:
編譯python代碼為字節碼(bytecode)
在虛擬機上面運行編譯好的python程序
CPython是用C語言編寫的,而C語言本身并不支持面向對象編程。正因為如此,在CPython代碼中有很多很有意思的設計,來實現這些原本不支持的的功能。:如PyObject。
PyObject是Python中所有對象的鼻祖,它只包含兩種東西:
ob_refcnt: 引用計數
ob_type: 指向另一種類型的指針
ob_refcnt引用計數用于接下來要說明的垃圾收集。
2.垃圾回收機制
2.1 垃圾回收簡單說明
Python中的垃圾回收回收機制采用引用計數的策略來實現,當一個對象的ob_refcnt大于0,說明存在引用,此時改對象不會進行垃圾回收。當一個對象 的ob_refcnt的引用數目等于0的時候,說明該對象沒有任何引用,說明是一個閑置廢棄的對象,會進入垃圾回收的階段。
Python允許您使用sys模塊檢查對象的當前引用計數。可以使用sys.getrefcount(numbers),但是要記住,將對象傳遞給getrefcount()會使引用計數增加1。
下面我們幾段代碼來演示一下:
2.2 引用計數入門示例
import sys
a1 = [1, 2, 3]
print(sys.getrefcount(a1))
運行結果:
2
程序運行說明:
首先第一次賦值操作,很容易理解變量a1指向的對象[1,2,3]的引用次數為1,然后在調用sys.getrefcount(a1)的時候,會把形參認為是一個局部變量a1,不是全局變量a1,但是對應的值是一樣的,所以這個時候會增加一個引用次數,變成2。
2.3 賦值增加引用計數
import sys
a1 = [1, 2, 3]
print(id(a1))
print(sys.getrefcount(a1))
a2 = a1
print(sys.getrefcount(a1))
print(sys.getrefcount(a1))
print("--" * 20)
a3 = [1, 2, 3]
print(id(a3))
print(sys.getrefcount(a3))
運行結果:
4726471808
2
3
3
----------------------------------------
4726471888
2
程序說明: 第一部分和上面的例子是一樣的,但是增加一個id(a1)的方法,會打印出a1的內存地址。當執行a2 = a1的時候,增加了一個引用。sys.getrefcount(a1)是同一個,所以兩次執行也不會增加引用。雖然a1和a3對應的值是相同的,但是id值不一樣,相當是一個新的,所以計算計算引用從1開始計算,增加sys.getrefcount(a1)里面的一個,最后結果為2。
2.4 對象包含在其他數據結構中會增加引用次數
import sys
a1 = [1, 2, 3]
print(sys.getrefcount(a1))
a2 = [a1]
print(sys.getrefcount(a1))
a3 = (a1, )
print(sys.getrefcount(a1))
a4 = {"key1": a1}
print(sys.getrefcount(a1))
運行結果:
2
3
4
5
程序運行說明: 這部分是可以正常理解的。
但是當數據變化的時候,下面的例子,我找了資料也沒有具體說清楚:
import sys
a1 = 1
print(sys.getrefcount(a1))
a2 = [a1]
print(sys.getrefcount(a1))
a3 = (a1, )
print(sys.getrefcount(a1))
a4 = {"key1": a1}
print(sys.getrefcount(a1))
運行結果:
4378
4379
4380
4381
程序說明: 這部分的原因是由于Python中對象緩存造成的,對于一些數值較小的對象,會經常使用到,對這一部分對象存在內部的緩存機制。也就是會存在多個引用,具體多少數值,和運行平臺、解釋器、數值取值大小都有都有印象。 下面通過兩段簡單代碼來說明: 第一段: Python命令行執行
>>> a1=1
>>> id(a1)
140732194454592
>>> a2=1
>>> id(a2)
140732194454592
>>>
>>> b1=257
>>> id(b1)
1878299222992
>>> b2=257
>>> id(b2)
1878301364976
第二段: Pycharm中保存文件執行
a1 = 1
a2 = 1
print(id(a1))
print(id(a2))
?
b1 = 257
b2 = 257
print(id(b1))
print(id(b2))
?
b1 = 99999999999999999999999999999999999999999999999
b2 = 99999999999999999999999999999999999999999999999
print(id(b1))
print(id(b2))
運行結果:
140732194454592
140732194454592
2195360849840
2195360849840
2195386463936
2195386463936
通過兩組程序我們發現,雖然Python存在對象的緩存機制,但是對于不同的運行環境中,存在一定的差異。在命令行中,以整數為例:[-5, 256]這個區間的范圍會被緩存,但是在文件中,無論多大數值都會被緩存。
3.析構方法
3.1 析構方法說明
__del__方法稱為"析構方法",用于實現對象被銷毀時所需要的操作。比如:釋放對象占用的資源。使用場景:
打開的文件資源
網絡連接
數據庫操作
。。。
Python實現自動的垃圾回收,當對象沒有被引用時(引用計數為0),由垃圾回收器調用__del__方法。
我們也可以使用del語句手動刪除對象,從而保證調用__del__方法。
系統會自動提供__del__方法,一般不需要自定義析構方法。
3.2 代碼示例
代碼:
class Person:
def __init__(self, name):
self.name = name
def __del__(self):
print("銷毀對象:{0}".format(self.name))
p1 = Person("p1")
p2 = Person("p2")
# 使用del方法主動銷毀對象p2
del p2
print("程序結束")
運行結果:
銷毀對象:p2
程序結束
銷毀對象:p1
代碼說明:
因為手動調用del方法注銷p2對象,本質上還是調用對象p2本身的注銷機制,在注銷之前會調用自身的__del__()方法,所以第一行輸出銷毀對象:p2.
程序代碼運行結束,執行打印語句,所以第二行顯示:程序結束
python的垃圾回收器,對程序進行處理,發現對象p1目前仍占用內存,沒有被清除。啟動垃圾回收機制,類似步驟一,所以第三行輸出: 銷毀對象:p1
備注:
更多精彩博客,請訪問:聶發俊的技術博客
對應視頻教程,請訪問:python400
完整markdown筆記,請訪問: python400_learn_github
總結
以上是生活随笔為你收集整理的python垃圾回收 采用方式_python-面向对象-10-__del__析构方法/垃圾回收机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: system流怎么判断为空_并行流Par
- 下一篇: python打包出现乱码_python解