[英]Garbage Collector and gc module
當我懷疑以下短語時,我正在閱讀文檔:
由於收集器補充了Python中已經使用的引用計數,因此如果您確定程序不創建引用循環,則可以禁用收集器。
這是什么意思? 如果我禁用垃圾收集器( gc.disable()
),我會這樣做:
a = 'hi'
a = 'hello'
會'hi'
留在記憶中嗎? 我需要自己釋放記憶嗎?
我從那句話中理解的是,gc是一個額外的工具,特別是為了捕獲參考周期,如果它被禁用,內存仍然會使用對象的參考計數器自動清理,但不會管理參考周期。 是對的嗎?
在CPython中,當引用計數降為0時,會立即從內存中清除對象。
將a
重新綁定為'hello'
的那一刻, 'hi'
字符串對象的引用計數遞減。 如果它達到0,它將從內存中刪除。
因此,垃圾收集器只需要處理(間接或直接)引用彼此的對象,從而使引用計數不會下降到0。
字符串不能引用其他對象,因此對垃圾收集器不感興趣。 但是任何可以引用其他內容的東西(例如容器類型,如列表或字典,或任何Python類或實例)都可以產生循環引用:
a = [] # Ref count is 1
a.append(a) # A circular reference! Ref count is now 2
del a # Ref count is decremented to 1
垃圾收集器檢測到這些循環引用; 沒有別的東西引用a
,所以最終gc進程打破了圓圈,讓引用計數自然地降到0。
順便提一下,Python編譯器將字符串文字(例如'hi'
和'hello'
作為常量與生成的字節碼捆綁在一起,因此,始終至少有一個對這些對象的引用。 此外,源代碼中使用的與正則表達式[a-zA-Z0-9_]
匹配的字符串文字被實現 ; 制作單例以減少內存占用,因此使用相同字符串文字的其他代碼塊將保存對同一共享字符串的引用。
您對文檔的理解是正確的(但請參閱下面的警告)。
禁用GC時,引用計數仍然有效。 換句話說,循環引用將無法解析,但如果對象的引用計數降至零,則該對象將為GC'd。
警告:請注意,這不適用於與Python中的其他對象區別對待的小字符串(和整數)(它們實際上不是GC) - 請參閱Martijn Pieters的答案以獲取更多詳細信息。
請考慮以下代碼
import weakref
import gc
class Test(object):
pass
class Cycle(object):
def __init__(self):
self.other = None
if __name__ == '__main__':
gc.disable()
print "-- No Cycle"
t = Test()
r_t = weakref.ref(t) # Weak refs don't increment refcount
print "Before re-assign"
print r_t()
t = None
print "After re-assign"
print r_t()
print
print "-- Cycle"
c1 = Cycle()
c2 = Cycle()
c1.other = c2
c2.other = c1
r_c1 = weakref.ref(c1)
r_c2 = weakref.ref(c2)
c1 = None
c2 = None
print "After re-assign"
print r_c1()
print r_c2()
print "After run GC"
gc.collect()
print r_c1()
print r_c2()
它的輸出是:
-- No Cycle
Before re-assign
<__main__.Test object at 0x101387e90> # The object exists
After re-assign
None # The object was GC'd
-- Cycle
After re-assign
<__main__.Cycle object at 0x101387e90> # The object wasn't GC'd due to the circular reference
<__main__.Cycle object at 0x101387f10>
After run GC
None # The GC was able to resolve the circular reference, and deleted the object
None
在您的示例中,“hi”不會保留在內存中。 垃圾收集器檢測循環引用 。
這是python中循環引用的一個簡單示例:
a = []
b = [a]
a.append(b)
這里a
包含b
和b
包含a
。 如果禁用垃圾收集器,這兩個對象將保留在內存中。
請注意,某些內置模塊會導致循環引用。 它通常不值得禁用它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.