[英]Why does Python garbage collection with threads not work?
當我將線程定義為實例變量時,其他定義的對象不會被垃圾收集。 在此示例中,在循環的每次迭代中都會創建一個數組緩沖區,該緩沖區從不進行垃圾回收:
import array
import gc
import threading
from pympler import muppy
class A():
def __init__(self):
self.buffer = array.array('B')
# Defining a thread keeps array in memory
self.thread = threading.Thread(target=lambda *_: None)
if __name__ == '__main__':
for i in range(10):
a = A()
# del a # needed
gc.collect()
print('Iteration {}:'.format(i))
obj = muppy.get_objects()
print('Array objects {}'.format(len(muppy.filter(obj, Type=array.ArrayType))))
print('Thread objects {}'.format(len(muppy.filter(obj, Type=threading.Thread))))
print('Running threads {}'.format(len(threading.enumerate())))
輸出是:
Iteration 0:
Array objects 1
Thread objects 2
Running threads 1
Iteration 1:
Array objects 2
Thread objects 3
Running threads 1
...
線程是否啟動+加入並不重要。 對象緩沖區或self.thread 的顯式刪除允許垃圾收集。 我無法理解這種行為,希望得到一些解釋。 在我的生產代碼中,此功能最終會導致 python 實例的內存不足終止。
obj = muppy.get_objects()
是內存中所有對象的列表(因此是對所有對象的引用)。
由於在覆蓋obj
變量之前執行了下一次迭代的垃圾收集,因此muppy.get_objects()
操作變得累積——我在使用muppy
時也陷入了一個陷阱。
簡而言之:
gc.collect()
:不影響我們的變量obj = ...
: muppy
看到所持線程參考a
gc.collect()
:第一輪創建的A
實例不再被a
引用但仍然被obj
引用 => 不能被垃圾回收obj = ...
: muppy
看到a
引用的新線程和obj
引用的舊線程 使用muppy
的經驗法則:在再次調用muppy.get_objects()
之前,請務必刪除對對象列表的引用,否則您可能會感到驚訝。
將一個簡單的del obj
附加到循環的末尾會導致
Iteration 0:
Array objects 1
Thread objects 2
Running threads 1
Iteration 1:
Array objects 1
Thread objects 2
Running threads 1
Iteration 2:
Array objects 1
Thread objects 2
Running threads 1
...
PS 這與線程無關。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.