2017-04-10 109 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系統太弱而無法識別它們)。 –