代码之家  ›  专栏  ›  技术社区  ›  davidmytton

Python中的垃圾收集如何与类方法一起工作?

  •  3
  • davidmytton  · 技术社区  · 17 年前
    class example:
    
        def exampleMethod(self):
            aVar = 'some string'
            return aVar
    

    在本例中,在每次调用example.exampleMethod()之后,垃圾收集是如何工作的?一旦方法返回,是否将释放avar?

    4 回复  |  直到 17 年前
        1
  •  6
  •   S.Lott    17 年前

    变量永远不会解除分配。

    对象(在本例中是一个字符串,值为 'some string' 一次又一次地重复使用,这样就永远无法释放对象。

    当没有变量引用对象时,对象被释放。想想看。

    a = 'hi mom'
    a = 'next value'
    

    在这种情况下,第一个对象(带有值的字符串 'hi mom' )在执行第二条语句时不再引用脚本中的任何位置。对象( “嗨,妈妈” )可以从内存中删除。

        2
  •  4
  •   Paweł Polewicz    17 年前

    每次将对象分配给变量时,都会增加该对象的引用计数器。

    a = MyObject() # +1, so it's at 1
    b = a # +1, so it's now 2
    a = 'something else' # -1, so it's 1
    b = 'something else' # -1, so it's 0
    

    没有人能再访问我们在第一行创建的myObject对象了。

    当计数器达到零时,垃圾收集器释放内存。

    有一种方法可以做一个不增加引用计数器的复杂引用(例如,如果不希望某个对象仅仅因为在某个缓存dict中而被保存在内存中)。

    更多关于cpython的参考计数可以找到 here .

    python是语言,cpython是(相当流行的)实现。afaik语言本身没有指定 怎样 内存被释放。

        3
  •  3
  •   Nico    17 年前

    如果在不分配结果的情况下调用example.exampleMethod()(例如 a = example.exampleMethod() )然后它将被立即释放(在cpython中),因为cpython使用一个引用计数机制。字符串不是一个很好的示例,因为它们也有许多特定于实现的优化。字符串可以被缓存,并且不会被释放,以便可以重用。这特别有用,因为字符串在听写中用作键非常常见。

    同样,垃圾收集是特定于实现的,因此cpython、jython和ironpython将具有不同的行为,其中大多数行为都记录在各自的站点/手册/代码等中。如果您想了解一些,我建议您在定义了 德尔 ()方法,将对被垃圾收集的对象(它是析构函数)调用该方法。让它打印一些东西,这样你就可以追踪它的调用:)

        4
  •  0
  •   Silverfish    17 年前

    和nico的答案一样,这取决于您如何处理examplemethod返回的结果。python(或者cpython)使用引用计数。在该方法中,avar引用字符串,而在删除变量avar之后,变量avar可能不会留下任何引用,在这种情况下,它将被删除。

    下面是一个带有析构函数的自定义类的示例( 德尔 (self),打印出“对象1正在被销毁”或类似内容。gc是垃圾收集器模块,它自动删除引用计数为0的对象。它的存在是为了方便,否则就无法保证垃圾收集器何时运行。

    import gc
    class Noisy(object):
        def __init__(self, n):
            self.n = n
        def __del__(self):
            print "Object " + str(self.n) + " being destructed"     
    class example(object):
        def exampleMethod(self, n):
            aVar = Noisy(n)
            return aVar
    a = example()
    a.exampleMethod(1)
    b = a.exampleMethod(2)
    gc.collect()
    print "Before b is deleted"
    del b
    gc.collect()
    print "After b is deleted"
    

    结果如下:

    Object 1 being destructed
    While b lives
    Object 2 being destructed
    After b is deleted
    

    请注意,返回方法后会删除第一个有噪声的对象,因为它没有分配给变量,因此引用计数为0,但只有删除变量B后才会删除第二个,留下的引用计数为0。