我的脚本中有一个内存泄漏,我将其缩小到np.repeat
。从理论上讲,如果我有一些np.array
有自己的指针,叫做arr
,我做了一个arr_repeated = arr.repeat(10, axis = 0)
,然后在它们上面做del
,它们占用的内存应该被释放吗?
我正在检查:
psutil.Process(os.getpid()).memory_info().rss
更具体地说,以下代码中的memory_before
和memory_after
应该不同吗?
arr = np.array([[1,2,3,...], [...], [...]])
arr_repeated = arr.repeat(10, axis = 0)
memory_before = psutil.Process(os.getpid()).memory_info().rss
del arr
del arr_repeated
memory_after = psutil.Process(os.getpid()).memory_info().rss
我有
额外/python-numpy 1.13.1-2 [已安装]
在我的前辰/足弓上
仅仅因为您使用del
变量并不意味着立即释放内存。它只是删除变量的名称。Python 的引用计数机制和gc
负责释放内存。
因此,为了安全起见,您需要使用gc.collect
强制gc
清理可能包含循环引用的所有内容,否则 Python 将"随时"清理这些内容(可能仅在内存不足或特定时间后
(。例如,有关__del__
的文档包含以下注释:
注意
del x
不会直接调用x.__del__()
— 前者将x
的引用计数减少 1,后者仅在x
的引用计数达到零时才调用。一些可能阻止对象的引用计数变为零的常见情况包括:对象之间的循环引用(例如,双向链表或具有父指针和子指针的树数据结构(;对捕获异常的函数的堆栈帧上的对象的引用(存储在sys.exc_info()[2]
中的回溯使堆栈帧保持活动状态(;或者对堆栈帧上在交互模式下引发未经处理的异常的对象的引用(存储在sys.last_traceback
中的回溯使堆栈帧保持活动状态(。第一种情况只能通过明确打破循环来补救;第二个可以通过在回溯对象不再有用时释放对回溯对象的引用来解决,第三个可以通过将None
存储在sys.last_traceback
中来解决。启用循环垃圾回收器(默认情况下处于打开状态(时,将检测并清理垃圾循环引用。有关本主题的详细信息,请参阅 gc 模块的文档。
import numpy as np
import psutil
import os
import gc
arr = np.array([list(range(10000)), list(range(10000)), list(range(10000))])
arr_repeated = arr.repeat(10, axis = 0)
gc.collect()
memory_before = psutil.Process(os.getpid()).memory_info().rss
del arr
del arr_repeated
gc.collect()
memory_after = psutil.Process(os.getpid()).memory_info().rss
请注意,gc
还有一个检测泄漏的设置:gc.set_debug(gc.DEBUG_LEAK)
不确定它是如何工作的,但值得一试,而不是使用psutil
。