Python对象被我找不到的对象引用

时间:2016-10-03 19:12:50

标签: python object garbage-collection

我正在尝试从python中的内存中删除一个对象,并且我遇到了一个未被删除的对象。根据我的理解,如果没有对该对象的引用,垃圾收集器将在运行时取消分配内存。但是,如果我运行

,我删除了所有引用
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)

我收到了

的回复
  

并[d帧对象位于0x7f1eba291e50>]

     

0

那怎么不删除对象?

如果我

,我会得到所有对象实例的相同回复
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()

如何从对象中完全删除所有引用/知道所有框架对象是什么?

我认为对象框架(?)包含程序中所有对象的列表但我无法确认/找到一种方法来消除对象被所述神秘的引用(对我而言)对象框架。

非常感谢任何帮助

编辑:  好吧,我把代码改写成简单的形式,除了基础知识之外的所有内容

{{1}}

2 个答案:

答案 0 :(得分:0)

好的,谢谢cjhanks和user2357112,我想出了这个答案

问题在于,如果你运行程序,即使删除了某些内容,gc也不会在每天之后收集任何内容

要测试是否已删除,请改为运行

print len(gc.get_objects()) 

每次我经历一天""这样做表明python正在跟踪多少个对象。 现在有了这些信息并感谢评论我厌倦了将Grid更改为

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中看顶部)所以我的学习要点:

  • GC在我不知情的情况下运行
  • 在程序完成之前,内存已分配并且永远不会返回系统
  • Python将重用内存

答案 1 :(得分:0)

gc.get_referrers接受一个参数:它应该找到它的引用对象。

我无法想到gc.get_referrers不会返回任何结果的任何情况,因为为了将对象发送到gc.get_referrers,必须有对该对象的引用。

换句话说,如果没有对该对象的引用,则无法将其发送到gc.get_referrers

至少,会有来自globals()或当前execution frame(包含本地变量)的引用:

  

代码块在执行帧中执行。执行帧包含一些管理信息(用于调试),确定代码块执行完成后执行的持续时间和方式,并且(可能最重要的是)定义了两个命名空间,即本地和全局命名空间,它们会影响执行代码块。

从问题中查看示例的扩展版本:

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>

弱引用说对象已经死了,所以它确实被删除了。