class example:
def exampleMethod(self):
aVar = 'some string'
return aVar
在此示例中,每次调用example.exampleMethod()后垃圾收集如何工作?一旦方法返回,aVar会被解除分配吗?
答案 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。