python - 多次将 numpy.argpartition() 分配给列表元素时出现内存泄漏

标签 python numpy memory-leaks mutable

我无法理解代码中的内存泄漏。我想我的错误与 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/

相关文章:

c# - 为 Windows 手机 silverlight 页面实现 Dispose 和 Finalize

c++ - 如何删除C++中的指针数组?

python - Go 真的能比 Python 快那么多吗?

python - 在pytorch中创建自定义数据加载器时更改图像的尺寸

python - 卡方 numpy.polyfit (numpy)

python - 如何在 Python/Numpy 中向量化一个简单的 for 循环

python - numpy.searchsorted 有多个来源

java - 使用 JNI 从 C 调用 java 代码时发生内存泄漏

python - JSON解码错误 : using googletrans module

python - 这个数学运算程序是否已经存在?