python - 多次将 numpy.argpartition() 分配给列表元素时的内存泄漏
问题描述
我无法理解代码中的内存泄漏。我想我的错误与 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 手册中所述,“NumPy 切片创建视图而不是副本”。因此,原始数组的底层内存“直到从它派生的所有数组都被垃圾收集后才会被释放”。
在对大数组进行切片时,Numpy 文档还建议使用copy()
:“从大数组中提取一小部分时必须小心……在这种情况下,建议使用显式 copy()。”
测量内存使用情况
在您的两个示例中返回相同值的原因sys.getsizeof
是,“仅考虑直接归因于对象的内存消耗,而不考虑它所引用的对象的内存消耗。” 在您的示例中,您调用sys.getsizeof
了一个列表对象,因此它返回列表的大小并且不考虑其中 NumPy 数组的大小。
例如,sys.getsizeof([None for _ in data])
也会返回87624
.
numpy 数组的内存使用情况
要获取data
数组的大小,您可以sys.getsizeof
使用 adata
作为参数调用:
sys.getsizeof(data)
现在,要获取closest_neighbours
列表中所有数组的大小,您可以尝试以下操作:
sum(sys.getsizeof(x) for x in closest_neighbours)
请注意,如果列表包含任何views
. 如Python 文档中所述,sys.getsize
“将返回正确的结果 [对于内置对象],但这对于第三方扩展不一定适用,因为它是特定于实现的。” 在 NumPy 的情况下,视图view.__sizeof__()
将返回 96。
推荐阅读
- salesforce - 访问外部网站中的 Salesforce visualforce 页面(使用 API 或任何其他方法)
- python - pd.apply 中的不同 np.std 行为
- smtp - Alertmanager 无法通过端口 465 发送邮件
- asp.net-core-2.2 - 将 .net core 2.2 迁移到 .net standard 2.0 会导致警告
- javascript - THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs
- python - 如何在 Tensorflow 中计算整个数据集的统计数据(总和、均值、方差等)
- openscenegraph - 无法在 FBX 文件中嵌入纹理
- sharepoint - SharePoint WSP 部署未完成,因为 SharePoint 更新
- fortran - 带有格式化换行符的单个 Fortran WRITE 语句?
- html - 应用 xsl 时遇到问题:选择