2017-04-10 108 views
0

我正在使用python3。我遇到了一种奇怪的情况,只有在对象有办法确定是否有任何对象引用时才能解释这种情况。但是,这种行为似乎并没有影响python2.7。我已经放弃了对垃圾收集问题的解释,因为gc.disable()没有区别。只是为了澄清,这对我来说不是问题,但我真的很想知道这是怎么回事。对象可以跟踪其引用吗?


如果您对特定情况感兴趣,请参阅MWE。

我这个代码从matplotlib docs(matplotlib 2.0.0)剪断工作:

import matplotlib.pyplot as plt 
import numpy as np 
from datetime import datetime 

def update_title(axes): 
    axes.set_title(datetime.now()) 
    axes.figure.canvas.draw() 

fig, ax = plt.subplots() 

x = np.linspace(-3, 3) 
ax.plot(x, x*x) 
timer = fig.canvas.new_timer(interval=100) 
timer.add_callback(update_title, ax) 
timer.start() 
#timer_another_ref = timer 
#timer = None 
plt.show() 

现在,如果我取消对该行timer = None,计时器没有了(只在python3工作,正如我之前所说)。另一方面,如果我现在取消注释其他行,它会按预期工作。


作为旁注,我有两台电脑。一个是在ubuntu 14.04上运行python 3.4.3并使用后端Qt5Agg,另一个是在ubuntu 16.04上运行python 3.5.2并使用后端TkAgg。这种行为只在前者(我猜想它与后端相关)上出现。

回答

2

如果你想获得一个对象的引用计数,那么你可以使用:

sys.getrefcount(something) 

请注意,以下将输出2因为有一个临时的参考名单。

lst = [1, 2, 3] 
print(sys.getrefcount(lst)) 
+0

不知道那个谢谢! –

+0

因此,在这种情况下,计时器可能正在检查sys.getrefcount(self)。有趣。 – LGenzelis

1

嗯,它(几乎肯定)是由于垃圾收集。在CPython中,大量的垃圾回收是通过引用计数完成的,这与gc模块无关。 gc仅用于收集参考文献周期中的垃圾,在这种情况下,单独引用计数是无助的。例如:

class T: 
    def __del__(self): 
     print("going away") 

t = T() 
print("before") 
t = None # remove only reference to the object 
print("after") 

在CPython中的每一个版本发布过(甚至是那些以前gc存在),即打印:

before 
going away 
after 

现在更大胆的尝试:

x = T() 
y = T() 
x.ref = y 
y.ref = x 
print("before") 
x, y = None, None 
print("after") 

import gc 
gc.collect() 
print("after gc") 

xy ,反之亦然。这是“一个循环”。每个都可以从另一个到达,所以它们的引用计数不能低于1(除非x.ref和/或y.ref也反弹)。因此,在所有版本的CPython下,打印:

before 
after 

最初。在Python 3中,如此下去打印:

going away 
going away 
after gc 

但是Python 2下,那就只在打印:

after gc 

这一个不起眼的技术问题__del__方法是由于含循环垃圾对象; Python 2无法回收它们,但Python 3可以。

唉,我无法准确猜测你的例子中发生了什么。这需要在两种实现下研究fig.canvas.new_timer的源代码。

但底线足够清楚:如果你需要一个对象来保持活着,请确保它可以从你的代码中获得。在无法访问后,任何时候垃圾收集子系统或其他垃圾收集子系统都可以自由销毁。

+0

我一直认为''gc.disable()''完全阻止垃圾收集。所以有两个垃圾收集器,''gc.disable()''只是停止其中的一个。 – LGenzelis

+1

在CPython(Python的C实现)中,确实如此。引用计数(RC)系统是基础,并且不能被关闭 - Python程序通常会以一种凶猛的速度创建新的对象,没有RC系统,大多数程序会快速耗尽内存。独特的'gc'系统仅用于循环回收垃圾(RC系统太弱而无法识别它们)。 –