2015-03-25 62 views
1

我想删除所有引用一个内存位置的对象。如果我不知道他们的全名,该怎么办?如何删除在Python中引用对象的内存位置?

class Foo(object): 
    pass 


class Bar(object): 
    pass 

a = Foo() 
b = a 
c = Bar() 
c.a_ref = a 
c.b_ref = b 

for item in a, b, c.a_ref, c.b_ref: 
    print(id(item)) 

""" Out: 
140035270075472 
140035270075472 
140035270075472 
140035270075472 
""" 

UPD:

确定。我想删除linkport1.link,不用担心所有连接到它的其他端口(port2.link),它们也不得不消失。

class LINK(object): 
    pass 


class PORT(object): 

    def __init__(self, link=None): 
     self.link = link 

    def __repr__(self): 
     return str(id(self.link)) 

link = LINK() 

port1 = PORT() 
port2 = PORT() 
port1.link = port2.link = link 

print(id(link), port1, port2) 
# (140586778512720, 140586778512720, 140586778512720) 
del link 
print(port1, port2) 
# (140586778512720, 140586778512720) 
# want: (None, None) ??? 
+1

为什么?你真正的问题是什么? – 2015-03-25 07:35:52

+0

我是一个小更新的例子,也许它可以做不同,但我认为删除内存位置的想法是逻辑 – uralbash 2015-03-25 08:10:55

+0

如果我的答案有帮助,不要忘记接受它。谢谢! – 2015-03-26 13:42:47

回答

1

weakref模块。它保持对对象的引用,而不会阻止它被垃圾收集,如果其所有强引用都被删除。例如:

import weakref 

class LINK(object): 
    pass 

class PORT(object): 

    def __init__(self, link=None): 
     if link is not None: 
      self.link = weakref.ref(link) 
     else: 
      self.link = None 

    def __repr__(self): 
     if self.link is None: 
      return 'None' 
     o = self.link() 
     return 'None' if o is None else str(id(o)) 

link = LINK() 

port1 = PORT() 
port2 = PORT() 
port1.link = port2.link = weakref.ref(link) 

print(id(link), port1, port2) 
del link 
print(port1, port2) 

输出:

70741240 70741240 70741240 
None None 

注意,你可能还是要打电话gc.collect()在某些情况下,弱引用报告None之前。

+0

谢谢,这是我的预期。但其他答案对我也很有用! – uralbash 2015-03-30 10:38:18

1

你不能明确地释放内存。你需要做的是确保你不保留对象的引用。然后他们将被垃圾收集,释放内存。 顺便说一下,你可以打电话gc.collect()强制执行gc操作。

UPDATE:

您无法通过只删除其引用的一个删除一个对象的所有引用,因为你不还有谁仍然在使用这个对象知道。如果是这样,还会有另一个问题,如何防止他人删除我的对象而不承认我。

我认为你的问题的最佳解决办法是分别删除属性链接。

del link 
del port1.link 
del port2.link 

然后删除后得到无,你应该这样做:

... 
def __repr__(self): 
     repr_string = getattr(self, 'link', None) 
     return str(id(self.link)) if repr_string else None 
... 
+0

请参阅UPD:''gc.collect''没有解决我的问题 – uralbash 2015-03-25 08:13:06

+0

@uralbash检查我的更新 – 2015-03-25 08:32:18

+0

是的,但是如何获取所有链接的对象,如果它们可能会更改? – uralbash 2015-03-25 09:09:38

3

你不能在Python中显式释放内存。垃圾收集器负责为你做这件事。

你可以做的是保证所有对你的对象的引用都被清除。垃圾收集器与时代(如e1,e2和e3)一起工作,只有e3中的对象将在下一次迭代中清理。

如果没有对象的引用,对象只能从epoch eX到eY(其中Y> X)。所以你的对象从e1开始;如果你“清除”了所有的引用,在垃圾回收器的下一次迭代中,它们将被移动到e2;在下一个他们将被移动到e3,最后内存将被释放。

您可以更改垃圾收集器被调用的周期性,但我不会建议这样做。或者您可以使用gc.collect()强制垃圾回收器的调用,但正如我所说的,您的对象必须在清理之前先通过所有时代(这就是为什么gc.collector()的调用不适合您的原因)。只是为了澄清,一旦达到阈值(由gc跟踪的内存中的对象的数量),就会调用垃圾收集器。

如果你想在Python中诊断内存泄漏,你也可以使用objgraph库,这非常好。它用对象之间的所有链接和引用构建图形,并让您识别周期。当您认为所有引用都被清除时,循环是垃圾收集器不会释放对象的主要原因。这是一个很好的教程http://chase-seibert.github.io/blog/2013/08/03/diagnosing-memory-leaks-python.html

1

对我来说,你真正的问题听起来像你有一个图,其中PORT s是节点,LINK s是边缘。而且您的要求是,当您删除边缘时,边缘连接的两个节点也应该被删除。这可以通过覆盖节点的__del__方法来显式完成,以便删除它将删除连接的边。

Python将“内存”抽象化,并使用id为您提供内存位置(这实际上是CPython的实现细节),这是做这件事的一种片状方式。

相关问题