递归删除python字典

时间:2013-08-09 13:04:26

标签: python dictionary

我有大量代码,它使用一些自定义类和许多字典。许多类都将字典添加为属性。我发现它使用了太多内存,特别是如果我正在循环 - 即使我手动删除了一些类和dicts。

我担心的是,字典会被删除,但它们包含的对象仍然存在。我需要重构代码以获得更好的内存管理,但作为一个快速的解决方案,我希望我可以递归并且积极地删除字典。如何实现这一目标?

这是一个例子......

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”(例如没有引用对象)之后,它似乎也没有“释放”内存。我在我的机器上发现的结果是不可预测的。有时看起来内存会被冲洗,有时它似乎会继续使用。

2 个答案:

答案 0 :(得分:5)

如果词典中的对象在您删除了词典之后就存在了,那么它们应该存在,因为有些代码会引用它们。

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

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

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

    这就是为什么还有一个垃圾收集器清理它,虽然稍晚一点。引用计数在引用达到0时处理对象,垃圾收集器稍后开始播放。

    所以不需要递归删除任何东西,只需删除对字典的引用,让Python担心其余部分。

    此处还有另一个问题,提供更多细节:Why does python use both reference counting and mark-and-sweep for gc?

    您可以使用以下代码进行验证:

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

    这将向您显示__del__方法作为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")
    

    这将向您显示周期(xy相互引用)的处理方式不同。

    然后你有了这个,我将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")
    

答案 1 :(得分:3)

删除对象时,只是将引用删除到该对象。如果该对象的引用计数降为0,则将其从内存中删除,并将该对象保存到其他对象的任何引用。

例如,

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

因此无需递归删除任何内容。如果不再引用您的对象,则会自动清除它们。

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

相关问题