首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >多次将numpy.argpartition()分配给list元素时内存泄漏

多次将numpy.argpartition()分配给list元素时内存泄漏
EN

Stack Overflow用户
提问于 2020-02-06 10:56:33
回答 1查看 293关注 0票数 2

我很难理解代码中的内存泄漏。我想我的错误与numpy数组是可变的有关,因为它可以使用.copy()解决。

但我不明白为什么会这样。下面是内存泄漏的代码的一个最小示例,该代码在内存中使用大约1600 is:

代码语言:javascript
运行
复制
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,正如我所预期的那样。

代码语言:javascript
运行
复制
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])

最后的结果对两人都是一样的:

代码语言:javascript
运行
复制
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对象本身,为什么会导致内存泄漏呢?

EN

Stack Overflow用户

回答已采纳

发布于 2020-02-07 13:37:15

您的问题可以归结为下面的示例:

代码语言:javascript
运行
复制
import numpy as np

array = np.empty(10000)
view = array[:5]
copy = array[:5].copy()

在这里,view对象的内存使用量也将大大高于copy对象的内存使用量。

解释

正如在NumPy手册中所描述的,"NumPy切片创建了一个视图而不是一个副本“。因此,原始数组的底层内存“将不会释放,直到从它派生的所有数组都被垃圾收集”。

在对一个大数组进行切片时,Numpy文档还建议使用copy():“当从一个大数组中提取一小部分时,必须小心.在这种情况下,建议使用一个显式副本()。”

测量内存使用量

sys.getsizeof在两个示例中返回相同值的原因是,“只考虑了直接归因于对象的内存消耗,而不是它引用的对象的内存消耗”。在您的示例中,您在list对象上调用了sys.getsizeof,因此它返回列表的大小,而不考虑其中NumPy数组的大小。

例如,sys.getsizeof([None for _ in data])还将返回87624

numpy数组的内存使用

要获取data数组的大小,可以使用一个data作为参数调用sys.getsizeof

代码语言:javascript
运行
复制
sys.getsizeof(data)

现在,要获取closest_neighbours列表中所有数组的大小,可以尝试如下所示:

代码语言:javascript
运行
复制
sum(sys.getsizeof(x) for x in closest_neighbours)

请注意,如果列表包含任何views,则此操作将不起作用。正如Python文档中所述,sys.getsize“将为内置对象返回正确的结果,但对于特定于实现的第三方扩展来说,这不一定成立。”如果出现NumPy视图,view.__sizeof__()将返回96。

票数 2
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60093367

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档