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

时间:2009-05-09 15:03:39

标签: python garbage-collection

class example:

    def exampleMethod(self):
        aVar = 'some string'
        return aVar

在此示例中,每次调用example.exampleMethod()后垃圾收集如何工作?一旦方法返回,aVar会被解除分配吗?

4 个答案:

答案 0 :(得分:6)

变量永远不会被释放。

对象(在本例中为一个字符串,值为'some string'会一次又一次地重复使用,因此永远不会释放该对象。

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

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

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

答案 1 :(得分:4)

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

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对象了。

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

有一种方法可以制作一个不会增加引用计数器的棘手引用(例如,如果你不希望某个对象在内存中保留,只是因为它存在于某些缓存字典中)。

更多关于cPython的引用计数可以找到here

Python是语言,cPython是它(非常受欢迎)的实现。 Afaik语言本身没有指定如何释放内存。

答案 2 :(得分:3)

从您的示例中,如果您调用example.exampleMethod(),而不分配结果(例如。a = example.exampleMethod()),那么它将被立即释放(在CPython中),因为CPython使用引用计数机制。字符串不是一个很好的使用示例,因为它们还具有许多特定于实现的优化。字符串可以被缓存,并且不会被释放,以便可以重用它们。这特别有用,因为字符串非常常用作dicts中的键。

同样,垃圾收集特定于实现,因此CPython,Jython和IronPython将具有不同的行为,其中大多数记录在相应的站点/手册/代码/等上。如果你想稍微探讨一下,我建议你创建一个你定义了 del ()方法的类,该方法将被垃圾收集对象调用(它是析构函数)。让它打印一些东西,这样你就可以追踪它的召唤:)

答案 3 :(得分:0)

在Nico的回答中,它取决于你对exampleMethod返回的结果做了什么。 Python(或者反过来CPython)使用引用计数。在该方法期间,aVar引用该字符串,之后删除变量aVar,这可能不会引用任何引用,在这种情况下,它将被删除。

下面是一个自定义类的示例,该类具有析构函数( del (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

请注意,返回方法后会删除第一个Noisy对象,因为它没有分配给变量,所以引用计数为0,但第二个只在删除变量b后才删除引用计数为0。