如何删除python中引用对象的内存位置?

时间:2015-03-25 07:34:39

标签: python reference weak-references

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

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) ???

4 个答案:

答案 0 :(得分:3)

您无法在Python中明确释放内存。垃圾收集器负责为您完成此操作。

您可以做的是保证清除对象的所有引用。垃圾收集器使用时期(如e1,e2和e3),只有e3中的对象将在下一次迭代中清除。

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

您可以更改调用垃圾收集器的周期,但我不建议这样做。或者您可以使用gc.collect()强制调用垃圾收集器,但正如我所说,您的对象必须在清除之前经历所有时期(这就是为什么调用gc.collector()没有&#39} ;为你工作)。只是为了澄清,一旦达到阈值(gc跟踪的内存中的对象数量),就会调用垃圾收集器。

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

答案 1 :(得分:1)

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

<强>更新

您不能通过仅删除其中一个引用来删除对一个对象的所有引用,因为您不知道还有哪些人仍在使用此对象。如果是这样,还会有另一个问题,如何在不承认我的情况下阻止他人删除我的对象。

我认为您问题的最佳解决方案是单独删除属性链接。

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
...

答案 2 :(得分: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

答案 3 :(得分:1)

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

Python抽象出&#34;内存&#34;并且使用id为您提供内存位置(这实际上是CPython的实现细节)的事实是一种执行此操作的简单方法。