我一直在写一个长脚本,有时会构建大的字典和/或列表,我想知道是否可以通过使用del
删除它们来提高性能,当我完成使用它们后。或者留下这些对象让垃圾回收来处理是正常做法吗?这里应该采取什么最佳实践?谢谢。
我一直在写一个长脚本,有时会构建大的字典和/或列表,我想知道是否可以通过使用del
删除它们来提高性能,当我完成使用它们后。或者留下这些对象让垃圾回收来处理是正常做法吗?这里应该采取什么最佳实践?谢谢。
del
与free(3)
不等同。它并不能强制Python释放内存。它可能根本没有释放内存。您应该完全避免将其与内存使用关联在一起。
del
唯一做的是从其作用域中删除一个名称。(或者从集合中删除一个项目,或者删除一个属性。但我认为这不是您在这里讨论的内容。)
实际上,这个:
del foo
等价于这个:
del LOCAL_SCOPE['foo']
所以这并不会释放任何内存:massive_list = list(range(1000000))
same_massive_list = massive_list
del massive_list
因为它只是删除了名称massive_list
,而底层对象仍然有另一个名称same_massive_list
,因此它并没有消失。 del
不是控制Python内存管理的秘密钩子; 它只是请求Python触发其内存管理的几种方法之一。
(顺便说一下,CPython是引用计数+循环收集,而不是垃圾回收。 只要最后一个对它们的引用消失,对象就会立即释放。 垃圾不会等待被清除。 当然,其他实现的情况可能不同; 例如PyPy进行垃圾回收。)
现在,如果您使用的名称是列表/字典/任何东西的唯一名称,则del
肯定会导致其引用计数降为零,从而释放它。 但是,由于del
的语义实际上是关于删除名称的,因此在这种情况下我不会使用它。 我会让变量超出范围(如果可行),或将名称重新分配给空列表、None
或对您的程序有意义的任何内容。 您甚至可以原地清空列表,即使有多个名称指向同一列表也可以工作:
foo = list(range(1000000))
bar = foo
foo[:] = []
# Both `bar` and `foo` still refer to the original list, but now it's empty
你可以使用d.clear()
来清空字典。
我只会在类或模块作用域中使用del
来处理变量,这时我只是临时需要一些辅助值,但真的真的不想将其公开为API的一部分。虽然这种情况非常罕见,但这是我遇到的唯一一种实际上需要"删除这个变量名"语义的情况。
del foo[:]
更加简洁。 - nneonneodel
用于删除名称。列表和字典都有 .pop
,而列表有切片语法,因此几乎不需要特殊的构造;只有使用 del
才能删除变量(大概)。这也避免了扫描问题:当你看到 del super_duper_long_name[2]
时,直到读到行末,你才能确定它是哪种类型的 del
。 - Eeveedel
通常是不必要的。
在CPython中,当没有引用指向对象时,对象会被删除。 del
仅删除对对象的一个引用;如果仍然有其他引用指向该对象,则它将保留,并且del
实际上没有做任何事情来改善您的内存情况。
相反,仅将变量重新分配给另一个对象(例如,在循环的顶部创建一个新的空列表)也将导致对该对象的一个引用减少,隐式地执行与del
相同的操作。如果此时没有其他引用指向该对象,则它将立即被释放。
还要记住,当函数返回时,局部变量会被删除,因此您不需要显式地del
在函数中定义的任何名称。
例外情况是循环引用,其中两个(或多个)对象彼此引用,但通过名称实际上无法访问任何一个对象;Python定期进行垃圾回收,但如果您完成对象后打破循环,则可以更快地释放它们。 (这可能只需要一个del
!)然而,这种情况实用的情况可能非常罕见。
在IronPyothon(运行在.NET CLR上)或Jython(运行在JVM上)中,最佳的内存管理策略可能会有所不同,因为使用底层VM的垃圾回收器。