看下面两个函数,第一个返回函数闭包,第二个返回“类闭包”。objects
用于跟踪创建的对象。在这两种情况下,MyObject
的实例都被捕获在闭包中。在
import weakref
class MyObject(object):
pass
def leak1():
obj = MyObject()
objects[id(obj)] = weakref.ref(obj)
def inner():
return obj
return inner
def leak2():
obj = MyObject()
objects[id(obj)] = weakref.ref(obj)
class Inner(object):
__slots__ = () # edit
def __call__(self):
return obj
#def __del__(self):
# nonlocal obj
# del obj
return Inner()
def print_all_objects(s):
for id, ref in objects.items():
print(s, id, ref())
for leak in (leak1, leak2):
print(leak.__name__)
objects = {}
a = leak()
print_all_objects(1)
del a
print_all_objects(2)
如果运行此命令,将得到以下输出:
^{pr2}$这意味着在第一种情况下,obj
在函数闭包被删除之后被删除(这是我所期望的)。
但是在第二种情况下,obj
永远不会被删除。在python3中,可以通过使用nonlocal
和__del__
来修复,但在python2.7中不能这样做,因为nonlocal
不存在。在
所以我的问题是:为什么在类的情况下捕获的变量没有被删除;以及:如何在python2.7中删除它,而不使用一些奇怪的跟踪机制使用weakref
?在
你什么都不用做。在
CPython使用引用计数和垃圾回收器的组合来处理不需要的对象。在第一种情况下,删除带有
del a
的闭包将泄漏对象的refcount减少到0,并立即对其进行处理。在第二种情况下,Inner
类、它的__call__
方法和obj
之间存在一个引用循环。这个引用循环防止refcount下降到0,因此闭包不会立即被删除。但是,一旦垃圾收集器开始了下一个收集周期,则闭包将被处理。在如果要立即删除闭包,可以使用^{} 手动触发垃圾回收:
输出:
^{pr2}$相关问题 更多 >
编程相关推荐