我试图从 python 的内存中删除一个对象,但遇到一个未被删除的对象。根据我的理解,如果没有对该对象的引用,垃圾收集器将在运行时取消分配内存。但是,在我删除所有引用后,如果我运行
bar = Foo()
print gc.get_referrers(bar)
del bar
baz = gc.collect()
print baz
我收到了
的回复[< frame object at 0x7f1eba291e50>]
0
那么它为什么不删除对象呢?
如果我这样做,我会得到所有对象实例的相同回复
bar = [foo() for i in range(0, 10)]
for x in range(0,len(bar))
baz = bar[x]
del bar[x]
print gc.get_referrers(baz)
如何从对象中完全删除所有引用/知道所有对象上的框架对象是什么?
我认为这将是包含程序中所有对象列表的对象框架(?),但我无法确认/找到一种方法来消除对象被所述神秘(对我来说)对象框架引用.
任何帮助将不胜感激
编辑: 好吧,我将代码重写为简单的形式,去掉了除了基础知识之外的所有内容
import random, gc
class Object():
def __init__(self):
self.n=None
self.p=None
self.isAlive=True
def setNext(self,object):
self.n=object
def setPrev(self, object):
self.p=object
def getNext(self):
return self.n
def getPrev(self):
return self.p
def simulate(self):
if random.random() > .90:
self.isAlive=False
def remove(self):
if self.p is not None and self.n is not None:
self.n.setPrev(self.p)
self.p.setNext(self.n)
elif self.p is not None:
self.p.setNext(None)
elif self.n is not None:
self.n.setPrev(None)
del self
class Grid():
def __init__(self):
self.cells=[[Cell() for i in range(0,500)] for j in range(0,500)]
for x in range(0,100):
for y in range(0,100):
for z in range(0,100):
self.cells[x][y].addObject(Object())
def simulate(self):
for x in range(0,500):
for y in range(0,500):
self.cells[x][y].simulate()
num=gc.collect()
print " " + str(num) +" deleted today."
class Cell():
def __init__(self):
self.objects = None
self.objectsLast = None
def addObject(self, object):
if self.objects is None:
self.objects = object
else:
self.objectsLast.setNext(object)
object.setPrev(self.objectsLast)
self.objectsLast = object
def simulate(self):
current = self.objects
while current is not None:
if current.isAlive:
current.simulate()
current = current.getNext()
else:
delete = current
current = current.getNext()
if delete.getPrev() is None:
self.objects = current
elif delete.getNext() is None:
self.objectsLast = delete.getPrev()
delete.remove()
def main():
print "Building Map..."
x = Grid()
for y in range (1,101):
print "Simulating day " + str(y) +"..."
x.simulate()
if __name__ == "__main__":
main()
gc.get_referrers
采用一个参数:应该找到其引用者的对象。
我想不出任何情况下
gc.get_referrers
不会返回任何结果 (实际上存在这种情况,正如 Neil 评论的那样,因为 GC 不会跟踪所有内容,但这与这里无关),因为为了发送对象到 gc.get_referrers
,必须有对该对象的引用。
换句话说,如果没有对该对象的引用,就不可能将其发送到
gc.get_referrers
。
至少,会有来自
globals()
或当前执行框架(包含局部变量)的引用:
代码块在执行帧中执行。执行框架包含一些管理信息(用于调试),确定代码块执行完成后在何处以及如何继续执行,并且(也许最重要的是)定义两个影响代码执行的命名空间:本地命名空间和全局命名空间块。
查看问题中示例的扩展版本:
class Foo(object):
pass
def f():
bar = [Foo() for i in range(0, 10)]
for x in range(0, len(bar)):
# at this point there is one reference to bar[x]: it is bar
print len(gc.get_referrers(bar[x])) # prints 1
baz = bar[x]
# at this point there are two references to baz:
# - bar refernces it, because it is in the list
# - this "execution frame" references it, because it is in variable "baz"
print len(gc.get_referrers(bar[x])) # prints 2
del bar[x]
# at this point, only the execution frame (variable baz) references the object
print len(gc.get_referrers(baz)) # prints 1
print gc.get_referrers(baz) # prints a frame object
del baz
# now there are no more references to it, but there is no way to call get_referrers
f()
有一个更好的技巧来检测是否有引用者:
weakref
。
weakref
模块提供了一种创建对不计数对象的弱引用的方法。它的意思是,即使存在对某个对象的弱引用,当没有其他引用对该对象时,该对象仍然会被删除。它也不计入 gc.get_referrers
。
所以:
>>> x = Foo()
>>> weak_x = weakref.ref(x)
>>>
>>> gc.get_referrers(x) == [globals()] # only one reference from global variables
True
>>> x
<__main__.Foo object at 0x000000000272D2E8>
>>> weak_x
<weakref at 0000000002726D18; to 'Foo' at 000000000272D2E8>
>>> del x
>>> weak_x
<weakref at 0000000002726D18; dead>
弱引用说对象已经死了,所以确实被删除了。
好的,感谢 cjhanks 和 user2357112 我想出了这个答案
问题是,如果您运行该程序,即使删除了某些内容,GC 也不会每天收集任何内容
为了测试它是否被删除,我改为运行
print len(gc.get_objects())
每次我经历“一天”这样做时,都会显示 python 正在跟踪多少个对象。 现在有了这些信息并感谢评论,我厌倦了将网格更改为
class Grid():
def __init__(self):
self.cells=[[Cell() for i in range(0,500)] for j in range(0,500)]
self.add(100)
def add(self, num):
for x in range(0, 100):
for y in range(0, 100):
for z in range(0, num):
self.cells[x][y].addObject(Object())
def simulate(self):
for x in range(0,500):
for y in range(0,500):
self.cells[x][y].simulate()
num=gc.collect()
print " " + str(num) +" deleted today."
print len(gc.get_objects())
然后在过程中调用 Grid.add(50) 。我的程序内存分配没有增加(在Bash中观看top)所以我的学习要点: