以前都听说Python循环引用会导致引用数无法清零,所以不能垃圾回收,会内存泄漏,需要删除引用关系或者用gc.collect()才能进行正常垃圾回收。
但做了下实验,好像还是会自动回收循环引用的变量,在约44对循环引用变量时会首次清理,之后大约每产生200对的垃圾就会清一次,但也没清干净,总是会有残留上几个,而且听说了改__del__会影响垃圾回收,实质上也不会影响。
进程内存监控,可以看出内存大小基本没变,还是符合认知的。
====运行环境====
win10 1903
Python 3.7.5 64bit
=====代码=====
import psutil
class A:
t = 0
def __del__(self):
A.t += 1
class B:
t = 0
def __del__(self):
B.t += 1
if __name__ == '__main__':
pid = os.getpid()
at, bt = 0, 0
for i in range(10000):
a, b = A(), B()
a.b, b.a = b, a
#del a, b
if A.t != at or B.t != bt:
print(f'No_{i}: (d_i: {i - at}, d_a: {A.t - at}, d_b: {B.t - bt})')
print('Used Memory:', psutil.Process(pid).memory_info().rss / 1024 / 1024, 'MB')
at, bt = A.t, B.t
====打印结果====
No_44: (d_i: 44, d_a: 43, d_b: 43)
Used Memory: 13.69921875 MB
No_236: (d_i: 193, d_a: 190, d_b: 190)
Used Memory: 13.8046875 MB
No_431: (d_i: 198, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_626: (d_i: 200, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_822: (d_i: 202, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_1017: (d_i: 203, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_1212: (d_i: 204, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_1407: (d_i: 206, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_1603: (d_i: 208, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_1798: (d_i: 209, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_1993: (d_i: 210, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_2188: (d_i: 212, d_a: 212, d_b: 212)
Used Memory: 13.8046875 MB
No_2384: (d_i: 196, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_2579: (d_i: 197, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_2774: (d_i: 198, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_2969: (d_i: 200, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_3165: (d_i: 202, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_3360: (d_i: 203, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_3555: (d_i: 204, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_3750: (d_i: 206, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_3946: (d_i: 208, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_4141: (d_i: 209, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_4336: (d_i: 210, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_4531: (d_i: 212, d_a: 211, d_b: 211)
Used Memory: 13.8046875 MB
No_4727: (d_i: 197, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_4922: (d_i: 198, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_5117: (d_i: 199, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_5312: (d_i: 201, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_5508: (d_i: 203, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_5703: (d_i: 204, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_5898: (d_i: 205, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_6093: (d_i: 207, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_6289: (d_i: 209, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_6484: (d_i: 210, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_6679: (d_i: 211, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_6874: (d_i: 213, d_a: 211, d_b: 211)
Used Memory: 13.8046875 MB
No_7070: (d_i: 198, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_7265: (d_i: 199, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_7460: (d_i: 200, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_7655: (d_i: 202, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_7851: (d_i: 204, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_8046: (d_i: 205, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_8241: (d_i: 206, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_8436: (d_i: 208, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_8632: (d_i: 210, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_8827: (d_i: 211, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_9022: (d_i: 212, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_9217: (d_i: 214, d_a: 211, d_b: 211)
Used Memory: 13.8046875 MB
No_9413: (d_i: 199, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_9608: (d_i: 200, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
No_9803: (d_i: 201, d_a: 193, d_b: 193)
Used Memory: 13.8046875 MB
No_9998: (d_i: 203, d_a: 194, d_b: 194)
Used Memory: 13.8046875 MB
====实验结束====
之前了解Python3的print是线程安全的,但在这个垃圾回收的实验里,如果在__del__函数里添加print,在自动回收垃圾时有一定概率(概率小于20%)报出非阻塞的错误。
不过似乎只在Power shell会报错,在cmd里似乎不会报错,但考虑到cmd的输出远快于Power shell,可能是达不到并发标准所以在cmd才不报错。
而且是在此期间所有同时被回收的对象都会同时报错,还不太了解什么原因,不知道是不是并发回收对象的问题。
报错信息如下,一般一出就是4百条同时来:
RuntimeError: reentrant call inside <_io.BufferedWriter name='<stdout>'>
================================
其实原因还是很清楚的,就是不可重入,和线程安全是两回事。