递归删除python字典

递归删除python字典,python,dictionary,Python,Dictionary,我有大量的代码,使用了一些自定义类和很多字典。许多类将字典添加为属性。我发现它占用了太多内存,尤其是在循环时——即使我手动删除了一些类和dict 我担心的是,词典正在被删除,但它们包含的对象仍然存在。我需要重构代码以实现更好的内存管理,但作为一个快速解决方案,我希望能够递归地、主动地删除字典。这将如何实现 这里有一个例子 def get_lrg(): return {1: np.zeros((1000,1000,100))} class H(): def add_lrg(sel

我有大量的代码,使用了一些自定义类和很多字典。许多类将字典添加为属性。我发现它占用了太多内存,尤其是在循环时——即使我手动删除了一些类和dict

我担心的是,词典正在被删除,但它们包含的对象仍然存在。我需要重构代码以实现更好的内存管理,但作为一个快速解决方案,我希望能够递归地、主动地删除字典。这将如何实现

这里有一个例子

def get_lrg():
    return {1: np.zeros((1000,1000,100))}

class H():
    def add_lrg(self):
        fd = get_lrg()
        self.lrg = fd

for cls in ['a', 'b', 'c', 'd']:
    exec('{0} = H()'.format(cls) )
    exec('{0}.add_lrg()'.format(cls) )

del a
del b
del c
del d
另外,在Ipython中玩一玩:

fd = get_lrg()
fd2 = get_lrg()
F = {1: fd, 2: fd2}
F = {}
F = {1: fd, 2: fd2}
del F[1]

del F

并观察python应用程序的内存使用情况。。。即使在删除字典“F”之后,它也不会“释放”内存(例如,没有对对象的引用)。我在我的机器上发现结果是不可预测的。有时内存看起来确实被刷新了,但有时它似乎仍在使用。

删除对象时,您只是删除了对该对象的引用。如果该对象的引用计数下降到0,则该对象将从内存中删除,并带走该对象对其他对象的所有引用

例如,字典不包含任何对象。它们包含的全部内容都是对其他对象的引用。如果删除对字典的所有引用,它将自动清理、删除,并且它的所有引用也将消失。字典引用的任何键或值的引用计数将下降1;反过来,如果计数下降到0,它们将被清除

因此,不需要递归删除任何内容。如果对象不再被引用,它们将自动清理


请注意,即使Python释放对象,也不一定会占用进程内存。操作系统能够并且确实将内存分配给进程,以减少内存流失;进程可能需要再次增加内存使用量,除非其他地方迫切需要内存,否则分配将保留一段时间。

如果在您清除字典后字典中的对象仍然存在,那么它们应该存在,因为某些代码引用了它们

Python有两种处理内存的方法:

  • 参考计数
  • 标记并清除垃圾收集器
  • 删除词典时,将删除对相关对象的引用。如果这是对这些对象的最后一次引用,它们将自动为您释放

    但是,如果对象之间存在循环,则引用计数是不够的,因为这将导致循环中的所有对象至少有一个活动引用,即使不存在外部引用

    这就是为什么还有一个垃圾收集器来清理这些垃圾,尽管只是在稍晚的时候。引用计数负责处理对象当引用达到0时,垃圾收集器将在稍晚一点开始工作

    因此,不需要递归地删除任何内容,只需删除对字典的引用,让Python来处理其余的内容

    这里还有另一个问题,因此可以提供更多的细节:

    您可以使用以下代码来验证这一点:

    class X:
      def __del__(this):
        print("deleted")
    
      def __init__(this):
        print("constructed")
    
    print("before")
    x = X()
    print("after")
    del x
    print("done")
    
    这将向您显示
    \uuu del\uu
    方法作为
    del x
    语句的一部分执行

    那么你有这个:

    class X:
      def __del__(this):
        print("deleted")
    
      def __init__(this):
        print("constructed")
    
    print("before")
    x = X()
    y = X()
    x.y = y
    y.x = x
    print("after")
    del x
    del y
    print("done")
    
    这将向您显示循环(x和y都相互引用)的处理方式不同

    然后你有了这个,我将
    x
    存储到字典中,然后删除字典,
    x
    对象与字典一起被删除:

    class X:
      def __del__(this):
        print("deleted")
    
      def __init__(this):
        print("constructed")
    
    print("before")
    d = {"x": X()}
    print("after")
    del d
    print("done")
    

    你在找这样的东西吗:?相关:我添加了一些细节来说明我在说什么,但与此同时,还有一些进一步的讨论…@John:不要把内存分配和内存使用混为一谈。操作系统可以自由地将内存分配给进程,即使它们不再需要内存。因此,可能是延迟导致了我的问题。问题是我不能确定(毫无疑问,由于一些糟糕的代码)所有引用都被删除了……这是一个不同的问题,毫无疑问,这是您需要解决的问题,但这并不是因为Python没有清理保留在字典中的对象。如果他们不想死,就必须有别的东西让他们活着。在第二个/中间代码示例中,我试图激发垃圾收集器来处理我的对象,但它没有。毫无疑问,它会在一段时间后处理好它,但我并没有费心去弄清楚它需要多长时间或者如何激怒它。