新聞中心
在python中的垃圾回收機制主要是以引用計數(shù)為主要手段以標記清除和隔代回收機制為輔的手段 ??梢詫却嬷袩o效數(shù)據(jù)的自動管理!在這篇文章,帶著這個問題來一直往下看:怎么知道一個對象能不能被調用了呢?

創(chuàng)新互聯(lián)長期為上1000+客戶提供的網(wǎng)站建設服務,團隊從業(yè)經(jīng)驗10年,關注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務;打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為桓仁企業(yè)提供專業(yè)的做網(wǎng)站、網(wǎng)站設計,桓仁網(wǎng)站改版等技術服務。擁有10年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
回顧內存地址
Python中的任何變量都有對應的內存引用,也就是內存地址。
如果不是容器類型,那么直接引用和賦值,內存地址都是不會的。
- >>> a = 1
- >>> b = 1
- >>> id(a)
- 140709385600544
- >>> id(b)
- 140709385600544
如果在內存中創(chuàng)建了一個list對象(容器),而且對該對象進行了引用。那么b = [1,2]和c = a有什么區(qū)別?
- >>> a = [1,2]
- >>> b = [1,2]
- >>> id(a)
- 1966828025736
- >>> id(b)
- 1966828044488
- >>> c = a
- >>> id(c)
- 1966828025736
首先在內存1966828025736處創(chuàng)建了一個列表 [1,2],然后定義了一個名為a的變量。b = [1,2]會新開一個內存地址,c = a直接賦值直接引用[1,2]的內存地址。
引用計數(shù)
在一些代碼中,如果存在一些變量但是沒有用,會造成內存空間,因此叫做垃圾,所以要回收。
引用計數(shù)也是一種最直觀,最簡單的垃圾收集技術。原理非常簡單,每一個對象都包含了兩個頭部信息,一個是類型標志符,標識這個對象的類型;另一個是計數(shù)器,記錄當前指向該對象的引用數(shù)目,表示這個對象被多少個變量名所引用。
CPython 使用引用計數(shù)來管理內存,所有 Python 腳本中創(chuàng)建的實例,都會有一個引用計數(shù),來記錄有多少個指針指向它。當引用計數(shù)只有 0 時,則會自動釋放內存。
在Python中通過sys.getrefcount查看引用計數(shù)的方法,
- print(sys.getrefcount())
注意調用getrefcount()函數(shù)會臨時增加一次引用計數(shù),得到的結果比預期的多一次。
比如,下面這個例子中,a 的引用計數(shù)是 3,因為有 a、b 和作為參數(shù)傳遞的 getrefcount 這三個地方,都引用了一個空列表。
- >>> import sys
- >>> a = []
- >>> b = a
- >>> print(sys.getrefcount(a))
- 3
我們通過一些例子來看下,可以使python對象的引用計數(shù)增加或減少的場景。
- import sys
- a = []
- # 兩次引用,一次來自 a,一次來自 getrefcount
- print(sys.getrefcount(a))
- def func(a):
- # 四次引用,a,python 的函數(shù)調用棧,函數(shù)參數(shù),和 getrefcount
- print(sys.getrefcount(a))
- func(a)
- # 兩次引用,一次來自 a,一次來自 getrefcount,函數(shù) func 調用已經(jīng)不存在
- print(sys.getrefcount(a))
- ########## 輸出 ##########
- 2
- 4
- 2
引用計數(shù)是用來記錄對象被引用的次數(shù),每當對象被創(chuàng)建或者被引用時將該對象的引用次數(shù)加一,當對象的引用被銷毀時該對象的引用次數(shù)減一,當對象的引用次數(shù)減到零時說明程序中已經(jīng)沒有任何對象持有該對象的引用,換言之就是在以后的程序運行中不會再次使用到該對象了,那么其所占用的空間也就可以被釋放了了。
計數(shù)增加和減少
下面引用計數(shù)增加的場景:
- 對象被創(chuàng)建并賦值給某個變量,比如:a = 'ABC'
- 變量間的相互引用(相當于變量指向了同一個對象),比如:b=a
- 變量作為參數(shù)傳到函數(shù)中。比如:ref_method(a),
- 將對象放到某個容器對象中(列表、元組、字典)。比如:c = [1, a, 'abc']
引用計數(shù)減少的場景:
- 當一個變量離開了作用域,比如:函數(shù)執(zhí)行完成時,執(zhí)行方法前后的引用計數(shù)保持不變,這就是因為方法執(zhí)行完后,對象的引用計數(shù)也會減少,如果在方法內打印,則能看到引用計數(shù)增加的效果。
- 對象的引用變量被銷毀時,比如del a或者del b。注意如果del a,再去獲取a的引用計數(shù)會直接報錯。
- 對象被從容器對象中移除,比如:c.remove(a)
- 直接將整個容器銷毀,比如:del c
- 對象的引用被賦值給其他對象,相當于變量不指向之前的對象,而是指向了一個新的對象,這種情況,引用計數(shù)肯定會發(fā)生改變。(排除兩個對象默認引用計一致的場景)。
- import sys
- def ref_method(str):
- print(sys.getrefcount(str))
- print("我調用了{}".format(str))
- print('方法執(zhí)行完了')
- def ref_count():
- # 引用計數(shù)增加的場景
- print('測試引用計數(shù)增加')
- a = 'A'
- print(sys.getrefcount(a))
- b = a
- print(sys.getrefcount(a))
- ref_method(a)
- print(sys.getrefcount(a))
- c = [1, a, 'abc']
- print(sys.getrefcount(a))
- # 引用計數(shù)減少的場景
- print('測試引用計數(shù)減少')
- del b
- print(sys.getrefcount(a))
- c.remove(a)
- print(sys.getrefcount(a))
- del c
- print(sys.getrefcount(a))
- a = 783
- print(sys.getrefcount(a))
- if __name__ == '__main__':
- ref_count()
- ########## 輸出 ##########
- 測試引用計數(shù)增加
- 78 #77+1 77在函數(shù)中是隨機的
- 79
- 81
- 我調用了A
- 方法執(zhí)行完了
- 79
- 80
- 測試引用計數(shù)減少
- 79
- 78
- 78
- 4
本文已收錄 GitHub,傳送門~[2] ,里面更有大廠面試完整考點,歡迎 Star。
當前標題:深入Python中引用計數(shù)
文章路徑:http://m.5511xx.com/article/cdocohs.html


咨詢
建站咨詢
