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

How to remove memory location that is referenced objects in 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
"""

更新:

好的。我想删除 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) ???

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

更新:

您不能通过仅删除一个对象的引用来删除对一个对象的所有引用,因为您不知道还有谁仍在使用该对象。如果是这样,还有一个问题,如何防止别人在不承认我的情况下删除我的对象。

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

del link
del port1.link
del port2.link

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

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

请参阅 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

请注意,在某些情况下,您可能仍需要在弱引用报告 None 之前调用 gc.collect()

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

您可以做的是保证清除所有对您对象的引用。垃圾收集器与 epochs(如 e1、e2 和 e3)一起工作,并且只有 e3 中的对象才会在下一次迭代中被清理。

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

您可以更改调用垃圾收集器的周期,但我不建议这样做。或者您可以使用 gc.collect() 强制调用垃圾收集器,但正如我所说,您的对象在被清理之前必须经过所有时期(这就是 gc.collector() 的调用对您不起作用的原因) .澄清一下,一旦达到阈值(gc 跟踪的内存中的对象数),就会调用垃圾收集器。

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

你真正的问题,对我来说,听起来你有一个图,其中 PORTs 是节点,LINKs 是边。而你的要求是,当你删除一条边时,这条边所连接的两个节点也应该被删除。这可以通过覆盖节点的 __del__ 方法来显式完成,以便删除它会删除连接到的边。

Python 抽象出 "memory" 并使用 id 为您提供内存位置的事实(这实际上是 CPython 的实现细节)是一个这样做的片状方式。