我无法理解代码中的内存泄漏。我想我的错误与 numpy 数组是可变的有关,因为它可以使用 .copy()
来解决。
不过我不明白为什么会发生这种情况。下面是一个内存泄漏代码的最小示例,它使用了大约 1600MB 的内存:
import numpy as np
import sys
k_neighbours = 5
np.random.seed(42)
data = np.random.rand(10000)
for _ in range(3):
closest_neighbours = [
# get indices of k closest neighbours
np.argpartition(
np.abs(data-point),
k_neighbours
)[:k_neighbours]
for point in data
]
print('\nsize:',sys.getsizeof(closest_neighbours))
print('first 3 entries:',closest_neighbours[:3])
这里是相同的代码,但添加了 .copy()
。这似乎解决了问题,该程序的内存约为 80 MB,正如我所料。
for _ in range(3):
closest_neighbours = [
# get indices of k closest neighbours
np.argpartition(
np.abs(data-point),
k_neighbours
)[:k_neighbours].copy()
for point in data
]
print('\nsize:',sys.getsizeof(closest_neighbours))
print('first 3 entries:',closest_neighbours[:3])
两者的最终结果是相同的:
size: 87624
first 3 entries: [
array([ 0, 3612, 2390, 348, 3976]),
array([ 1, 6326, 2638, 9978, 412]),
array([5823, 5866, 2, 1003, 9307])
]
正如预期的那样。
我本以为np.argpartition()
创建了一个新对象,因此,我不明白为什么copy()
解决内存问题。即使情况并非如此,并且 np.argpartition()
以某种方式更改了 data
对象本身,为什么会导致内存泄漏?
最佳答案
您的问题可以归结为以下示例:
import numpy as np
array = np.empty(10000)
view = array[:5]
copy = array[:5].copy()
这里view
对象的内存使用量也会比copy
对象的内存使用量高很多。
说明
如 NumPy manual 中所述,“NumPy 切片创建 View 而不是副本”。因此,原始数组的底层内存“在所有派生自它的数组都被垃圾收集之前不会被释放。”
当对大数组进行切片时,Numpy 文档还建议使用 copy()
:
“从大数组中提取一小部分时必须小心……在这种情况下,建议使用显式的 copy() 。”
测量内存使用情况
原因sys.getsizeof
在两个示例中返回相同的值是因为“仅考虑直接归因于该对象的内存消耗,而不考虑它所引用的对象的内存消耗。”在您的示例中,您在列表对象上调用了 sys.getsizeof ,因此它返回列表的大小,并且不考虑其中 NumPy 数组的大小。
例如,sys.getsizeof([None for _ in data])
也将返回 87624
。
numpy 数组的内存使用情况
要获取 data
数组的大小,您可以调用 sys.getsizeof
,并将 data
作为其参数:
sys.getsizeof(data)
现在,要获取 closest_neighbours
列表中所有数组的大小,您可以尝试如下操作:
sum(sys.getsizeof(x) for x in closest_neighbours)
请注意,如果列表包含任何 View
,此操作将不起作用。如 Python Docs 中所述sys.getsize
“将返回正确的结果[对于内置对象],但这不一定适用于第三方扩展,因为它是特定于实现的。”对于 NumPy View view.__sizeof__()
将返回 96。
关于python - 多次将 numpy.argpartition() 分配给列表元素时出现内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60093367/