我的脚本中有内存泄漏,我将其缩小到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
我有
extra / python-numpy 1.13.1-2 [已安装]
在我的antergos / arch
上答案 0 :(得分:0)
仅仅因为您使用del
变量并不意味着内存会立即释放。它只删除变量的名称。 Pythons引用计数机制,gc
负责释放内存。
因此,为了安全起见,您需要使用gc.collect
强制gc
清除可能包含循环引用的所有内容,否则Python将“随时”清除这些内容(可能只有如果记忆力降低或在一定时间后)。
例如the documentation about __del__
包含此注释:
注意
del x
不直接调用x.__del__()
- 前者将x
的引用计数减1,后者仅在x
引用计数时调用达到零。可能阻止对象的引用计数变为零的一些常见情况包括:对象之间的循环引用(例如,双向链表或具有父指针和子指针的树数据结构);对捕获异常的函数的堆栈帧上的对象的引用(存储在sys.exc_info()[2]
中的回溯使堆栈帧保持活动状态);或者在交互模式下引发未处理异常的堆栈帧上的对象的引用(存储在sys.last_traceback
中的回溯使堆栈帧保持活动状态)。第一种情况只能通过明确打破周期来弥补;第二个可以通过释放对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
。