我一直在写一个很长的脚本,偶尔会构建大的字典和/或列表,我想知道del
在我用完它们后是否可以通过删除它们来提高性能。或者将这些对象留在周围由垃圾收集处理是正常的做法吗?这里的最佳做法是什么?谢谢。
3 回答
del
不等同于 free(3)。它不会强制 Python 释放内存。它可能根本不会释放内存。您应该避免将其完全与内存使用相关联。
唯一要做的就是从其范围del
中删除一个名称。(或者从集合中删除一个项目,或者删除一个属性。但我认为这不是你在这里谈论的内容。)
实际上,这:
del foo
相当于这个:
del LOCAL_SCOPE['foo']
所以这不会释放任何内存:
massive_list = list(range(1000000))
same_massive_list = massive_list
del massive_list
...因为它所做的只是删除name massive_list
。底层对象仍然有另一个名称,same_massive_list
所以它不会消失。 del
不是控制 Python 内存管理的秘密钩子;这只是要求Python调用其内存管理的几种方法之一。
(顺便说一句,CPython 是 refcounted + cycle-collected,而不是垃圾收集。对象在对它们的最后一个引用消失后立即被释放。垃圾不会到处等待被清理。当然,其他实现会有所不同东西;例如,PyPy 是垃圾收集的。)
现在,如果您使用的名称是 list/dict/whatever 的唯一名称,那么del
肯定会导致其引用计数降至零,因此它将被释放。 但是,由于del
's 语义实际上是关于删除names,所以在这种情况下我不会使用它。我只是让变量退出范围(如果可行),或者将名称重新分配给空白列表,或者None
,或者对您的程序有意义的任何内容。您甚至可以就地清空列表,即使同一个列表有多个名称,这也可以工作:
foo = list(range(1000000))
bar = foo
foo[:] = []
# Both `bar` and `foo` still refer to the original list, but now it's empty
你可以对 dict 做同样的事情d.clear()
。
我del
在名称上使用的唯一位置是在类或模块范围内,我暂时需要一些辅助值,但真的不想将它作为 API 的一部分公开。这确实很少见,但这是我遇到的唯一一个我真正想要“删除此名称”语义的情况。
del
通常是没有必要的。
在 CPython 中,当没有对它们的引用时,对象就会消失。del
仅删除对对象的一个引用;如果还有其他对该对象的引用,它将一直存在,并且del
实际上并没有改善您的记忆状况。
相反,简单地将变量重新分配给不同的对象(例如,在循环顶部创建一个新的空列表)也会最终减少对该对象的引用,隐含地执行与del
. 如果此时没有对该对象的其他引用,它将立即被释放。
还要记住,当函数返回时,局部变量会消失,因此您不需要显式地del
在函数中定义任何名称。
一个例外是循环引用,其中两个(或更多)对象相互引用,但实际上没有一个对象可以通过名称访问;Python 会定期对它们进行垃圾收集,但如果在处理完对象后打破循环,则可以更快地释放它们。(这可能只需要一个del
!)不过,这很有用的情况可能非常罕见。
在 IronPyothon(在 .NET CLR 上运行)或 Jython(在 JVM 上运行)中,最佳内存管理策略可能不同,因为使用了底层 VM 的垃圾收集器。
Python 的优点之一(与 C 等语言相比)是,通常您不必担心内存管理的细节,您可以专注于程序的目的。
所以我的建议是不要打扰,除非你有理由这样做(例如 python 正在吃掉你所有的 RAM)。