将numpy数组设置为无释放内存吗?
Posted
技术标签:
【中文标题】将numpy数组设置为无释放内存吗?【英文标题】:Does setting numpy arrays to None free memory? 【发布时间】:2016-05-20 21:28:41 【问题描述】:我有数百个非常大的矩阵,例如 (600, 800) 或 (3, 600, 800) 形状的矩阵。
因此,当我不再需要某些东西时,我想立即取消分配使用的内存。
我想:
some_matrix = None
应该做这项工作,还是只是将引用设置为 None 但在内存中的某个地方仍然分配了空间? (例如保留分配的空间以供将来重新初始化some_matrix
)
另外:有时我会切分矩阵,计算一些东西并将值放入缓冲区(一个列表,因为它一直被附加)。所以将列表设置为 None 肯定会释放内存,对吧?
或者是否存在某种unset()
方法,其中整个标识符及其引用的对象都被“删除”了?
【问题讨论】:
【参考方案1】:如果您必须执行以下操作,则不会释放内存,尽管会隐式生成 a
的副本:
a = np.ones((10000, 10000))
b = np.empty((10000, 10000))
b[:] = a
a = None
del a
相反,您可以执行以下操作,并且在执行a = None
后内存将被释放:
a = np.ones((10000, 10000))
b = np.empty((10000, 10000))
b[:] = np.copy(a)
a = None
del a
【讨论】:
【参考方案2】:您一定想看看garbage collection。与C/C++
等编程语言在不再需要空间时程序员必须自己释放动态分配的内存不同,python 有一个垃圾收集。这意味着python本身在necessary
时释放内存。
当你使用some_matrix = None
时,你将变量从内存空间中取消链接;引用计数器减少,如果达到0
,垃圾收集器将释放内存。
当您按照 MSeifert 的建议使用 del some_matrix
时,与答案所说的相反,内存不会立即释放。根据python doc,会发生这种情况:
删除名称会从本地或全局命名空间中删除该名称的绑定
幕后发生的事情是对内存空间的引用计数器减少了1
,与分配None
或使用del
无关。当此计数器达到0
时,垃圾收集器将来会free
内存空间。唯一的区别是,当使用del
时,从上下文中可以清楚地看出您不再需要该名称。
如果你看一下垃圾回收的文档,你会发现你可以自己调用它或者改变它的一些参数。
【讨论】:
gx
只是循环垃圾收集器,在这里不会有任何作用。当引用计数达到0
时,它在 CPython 中立即被释放,但这不是语言保证。例如,Jython 实现就不是这种情况,它使用 Java 垃圾收集器
@juanpa.arrivillaga 感谢您对某些实现的澄清。【参考方案3】:
Numpy
在引用计数器为零时删除数组(或者至少它会跟踪引用计数器并让操作系统收集垃圾)。
例如拥有
import numpy as np
a = np.linspace(0,100, 10000000)
a = None
将“立即”释放内存(首选方式是写del a
)同时
import numpy as np
a = np.linspace(0,100, 10000000)
b = a
a = None
不会释放任何东西。
您还提到了切片。切片只是对数据的一个视图,因此与第二个示例完全相同。如果您不删除引用同一数组的两个变量,操作系统将保留这些数组。
如果我做一些非常耗费内存的事情,我将始终坚持使用单独的函数来执行操作并且只返回真正需要的内容。函数会自行清理,以便释放任何中间结果(如果没有返回)。
【讨论】:
感谢您对功能/方法的澄清。我已经假设局部变量在 return 语句之后被丢弃(就像在 Java 或其他语言中一样),但很高兴听到 Python 确实在那里做了完全相同的事情。但是,del some_array
或一般del some_variable
应该始终是显式释放内存的首选?!
del
删除变量名,因此包括已删除变量在内的任何后续操作都会引发错误。另一方面,a=None
保留了变量 a
,因此您“可能”稍后会意外使用它,而不会意识到它实际上已被“删除”。
好的,谢谢。但是,第二种情况也不会使用del
释放任何东西?!因此,del
正在删除标识符及其引用,但是当没有其他标识符再引用它时,引用后面的对象就被删除了,对吧?因此,只要任何其他标识符引用该对象,例如您的示例中的b
,垃圾收集器就不会删除该对象?!
是的,我意识到我的解释有点含糊。就像@innoSPG 说的那样,python 只有在没有任何东西(以某种方式)引用它时才释放分配的内存。我试图用第二个例子来说明这个区别,其中其他东西引用了它。关于垃圾收集的问题有很好的答案(即***.com/questions/14969739/python-del-statement),所以我没有将它包含在答案中。但如果有要求,我可以这样做。
切片只是返回一个视图,所以它会保持arr
的整个内存活着。在您的情况下,我会在返回时复制 return arr[:3].copy()
以便可以释放 arr
(至少如果您想返回一小部分中间数组)。以上是关于将numpy数组设置为无释放内存吗?的主要内容,如果未能解决你的问题,请参考以下文章