簡體   English   中英

對於Python中的gc,動態創建的類總是“無法訪問”嗎?

[英]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開銷包含在一些特定函數中似乎是一種合理的折衷方案。

感謝所有花時間快速回答的人! :-)

聲明一個新式的類 - 靜態或通過type - 創建一個循環引用(實際上,不止一個)。 這是我能提供的最清晰的例子:

class Baz:
    pass

print(Baz in Baz.__mro__)
#True

Baz__dict__還有一些其他的循環引用,但是你只需要一個。

我沒有給你提供任何解決方法 - 這就是GC的用途,我很害怕。 如果您想進一步深入,我可以向您指出這個已經存在一段時間的錯誤報告

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM