6

我一直在写一个很长的脚本,偶尔会构建大的字典和/或列表,我想知道del在我用完它们后是否可以通过删除它们来提高性能。或者将这些对象留在周围由垃圾收集处理是正常的做法吗?这里的最佳做法是什么?谢谢。

4

3 回答 3

10

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 的一部分公开。这确实很少见,但这是我遇到的唯一一个我真正想要“删除此名称”语义的情况。

于 2013-03-12T19:57:20.937 回答
3

del通常是没有必要的。

在 CPython 中,当没有对它们的引用时,对象就会消失。del仅删除对对象的一个​​引用;如果还有其他对该对象的引用,它将一直存在,并且del实际上并没有改善您的记忆状况。

相反,简单地将变量重新分配给不同的对象(例如,在循环顶部创建一个新的空列表)也会最终减少对该对象的引用,隐含地执行与del. 如果此时没有对该对象的其他引用,它将立即被释放。

还要记住,当函数返回时,局部变量会消失,因此您不需要显式地del在函数中定义任何名称。

一个例外是循环引用,其中两个(或更多)对象相互引用,但实际上没有一个对象可以通过名称访问;Python 会定期对它们进行垃圾收集,但如果在处理完对象后打破循环,则可以更快地释放它们。(这可能只需要一个del!)不过,这很有用的情况可能非常罕见。

在 IronPyothon(在 .NET CLR 上运行)或 Jython(在 JVM 上运行)中,最佳内存管理策略可能不同,因为使用了底层 VM 的垃圾收集器。

于 2013-03-12T19:53:00.970 回答
0

Python 的优点之一(与 C 等语言相比)是,通常您不必担心内存管理的细节,您可以专注于程序的目的。

所以我的建议是不要打扰,除非你有理由这样做(例如 python 正在吃掉你所有的 RAM)。

于 2013-03-12T20:27:44.040 回答