Python del statement

31

在Python中调用变量的del。这是否会立即释放已分配的内存,还是仍在等待垃圾回收器收集?与Java不同,显式调用del并不影响内存何时被释放。


垃圾回收的意义在于你不必担心内存何时被释放。那么你为什么还要担心呢? - Waleed Khan
2
我正在处理大量的流量,并观察到内存泄漏问题。我几乎可以确定问题不在Python脚本中,但只是想确保一下。 - totoromeow
4个回答

39

del语句不会回收内存。它会移除一个引用,这将减少值的引用计数。如果计数为零,则可以回收内存。CPython会立即回收内存,无需等待垃圾回收器运行。

实际上,垃圾回收器只在回收循环结构时才需要使用。

正如Waleed Khan在他的评论中所说,Python的内存管理只是工作而已,你不必担心它。


2
我不相信CPython会将内存释放回操作系统,即使在它被回收后。 - martineau
3
我不确定还有其他怎样的说法:“CPython会立即回收内存,不需要等待垃圾回收器运行。” - Ned Batchelder
1
那个评论与我今天在SO上看到的很多内容相矛盾,但是将一个大型数据库表读入内存作为副本,然后使用del reference释放引用会导致内存被释放,因此垃圾回收被调用,并且(虽然没有时间保证)解释器将该内存返还给系统。如果我不将表分配给变量而是直接读取它,则它是一个孤立的对象,我必须显式地调用gc.collect()来查找并释放它。 - Pavel Komarov
1
@pvlkmrv 这听起来不对:如果您没有将表分配给一个变量,那么引用计数将为零,并且它将被回收。孤立的对象并不是问题,循环引用需要进行垃圾回收才能回收。 - Ned Batchelder
2
“del x” 对于垃圾回收和 “x= None” 并没有什么不同。它只是从 x 的值中删除了一个引用。 - Ned Batchelder
显示剩余5条评论

3
此外,del语句似乎比赋值为None更快(类似于Java的将null赋给变量以释放其内存的方式...)。
比较一下:
import time, math

def measure_del():
        start = time.time()
        for i in range(0,int(math.pow(10,8))):
                    a = "123"
                    del a # <--- !!!
        end = time.time()
        print(end-start)

def measure_none():
        start = time.time()
        for i in range(0,int(math.pow(10,8))):
                    a = "123"
                    a = None # <--- !!!
        end = time.time()
        print(end-start)

在空闲状态下运行的结果(运行在idle3.4中):

>>> measure_del()
3.9930295944213867
>>> measure_del()
3.7402305603027344
>>> measure_del()
3.8423104286193848
>>> measure_del()
3.753770351409912
>>> measure_del()
3.7772741317749023
>>> measure_del()
3.815058946609497

>>> measure_none()
4.052351236343384
>>> measure_none()
4.130320072174072
>>> measure_none()
4.082390069961548
>>> measure_none()
4.100180625915527
>>> measure_none()
4.071730375289917
>>> measure_none()
4.136169672012329

1
为什么程序员对那些对程序整体速度没有影响的事情的速度如此着迷呢? :) - Ned Batchelder
6
这个东西有点像一堆纸,比如你可以买500张80克或90克每平方米的纸张。如果你只写一张纸,你几乎不会注意到差别。但是如果你比较这两种包装,你会看到高度、重量和价格上明显的差异。编写良好的代码,将代码的可读性与机器级性能相平衡肯定是一个不错的主意。 - Barpfotenbaer
在某些情况下,您需要速度,因为您需要在缓冲区耗尽之前释放一些底层的C++内存,例如。正是这种情况促使我阅读了那个问题。 - Olivier RD

3

"删除名称会从本地或全局命名空间中删除该名称的绑定"。仅此而已,没有其他。它不会对名称指向的对象进行任何操作,除了减少其引用计数,如果引用计数不为零,则即使在GC运行时也不会收集对象。


0
关于删除: 有时您需要处理大型数据集,其中必须计算内存密集型操作并以递归方式将大量数据存储到变量中。为了节省RAM,在完成整个操作后,如果您不再在递归循环之外使用它,则应删除变量。您可以使用命令

del varname,然后是Python的垃圾收集器gc.collect()

关于速度: 速度是金融应用程序等具有监管要求的应用程序中最重要的因素。您必须确保操作速度在预期时间范围内完成。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接