[英]Are dynamically created classes always “unreachable” for gc in Python?
我有一個關於Python中的垃圾收集的問題。 在閱讀了一些有關為什么人們可能更喜歡運行帶有禁用垃圾收集*的Python程序的有見地的文章之后,我決定在我的代碼中搜索並刪除所有循環引用,以允許通過單獨的ref-count來銷毀對象。
為了找到現有的循環引用,我在我的unittest案例的tearDown方法中調用了gc.collect(),並在返回值> 0時打印出警告。 通過重構或使用弱引用可以輕松解決發現的大多數問題。
過了一會兒,我遇到了一個相當奇怪的問題,最好用代碼表達:
import gc
gc.disable()
def bar():
class Foo( object ):
pass
bar()
print( gc.collect() ) # prints 6
刪除對bar()的調用時,gc.collect()會按預期返回0。
看起來即使Foo是在函數欄的范圍內創建的並且永遠不會返回到外部,它仍然會使垃圾收集器找到無法訪問的對象。
將Foo移到bar的范圍之外時,一切正常。 但是,該解決方案不適用於我在受影響的代碼中嘗試解決的問題(動態創建ctypes.Structures用於序列化)。
以下兩種方法也不起作用:
import gc
gc.disable()
def bar():
type( "Foo", ( object, ), {} )
bar()
print( gc.collect() ) # prints 6 again
甚至非常'聰明':
import gc
gc.disable()
import weakref
def bar():
weakref.ref( type( "Foo", ( object, ), {} ) )
bar()
print( gc.collect() ) # still prints 6
最重要的是,這是一個實際工作的例子......但僅限於Python2:
import gc
gc.disable()
def bar():
class Foo(): # not subclassing object
pass
bar()
print( gc.collect() ) # prints 0 - finally?
然而,上面的代碼再次在Python3中打印出“6” - 我懷疑,因為所有用戶定義的類都是Python3中的新式類。
那么,我是否堅持Python2,Python3中奇怪的“無法訪問的對象”,或者我是否必須通過手動垃圾收集來跟進每次調用bar?
*(關於使用gc.disable()運行Python的文章)
http://pydev.blogspot.de/2014/03/should-python-garbage-collector-be.html http://dsvensson.wordpress.com/2010/07/23/the-garbage-garbage-collector-of -蟒蛇/
請參閱roippi的答案,了解為何上述行為符合預期。
但是為了將來參考,這里有一個小的解決方法,可以解決這個特殊的問題。 不是說禁用gc對任何人來說都是正確的,但如果你覺得這對你來說是正確的,那就是我這樣做的:
import gc
gc.disable()
def requiresGC( func ):
def func_wrapper( *args, **kwargs ):
result = func( *args, **kwargs )
gc.collect()
return result
return func_wrapper
@requiresGC
def bar():
class Foo( object ):
pass
bar()
print( gc.collect() ) # prints 0
但請注意,如果bar()是定期調用的函數,則此裝飾器將導致顯着減速。 然而,在我的情況下(序列化),情況並非如此,並且將gc開銷包含在一些特定函數中似乎是一種合理的折衷方案。
感謝所有花時間快速回答的人! :-)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.