You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Numpy数组拼接(concatenate/vstack)后内存占用居高不下问题排查

问题分析与解决方案

首先,你遇到的内存占用未回落问题,大概率不是Python垃圾回收的问题,而是和Numpy内存管理机制以及操作系统内存回收逻辑有关,咱们一步步拆解:

1. 为什么手动GC后内存没下降?

操作系统不会立刻回收闲置内存

当Python(或Numpy)释放内存时,操作系统通常不会马上把这些内存从进程的RSS(Resident Set Size,即psutil测量的内存)中移除。相反,它会把这块内存标记为「可用」,留给你的进程后续复用——只有当系统内存紧张时,操作系统才会将闲置内存回收给其他进程。

所以你用psutil看到的内存占用没降,不代表原数据集的内存没被释放,只是操作系统还没把这块内存收回去而已。

Numpy的内存池机制

Numpy自身维护了一个内存池,用来高效分配和管理数组内存。当你删除Numpy数组时,内存会被归还给Numpy的内存池,而非直接还给操作系统。这部分内存会被Numpy用来创建新数组,同样不会立刻体现在进程RSS的下降上。

2. 如何验证内存是否真的被释放?

你可以做个简单测试来确认:

data_set = _get_data('someName')
gc.collect()
# 创建一个和原training_data尺寸相近的数组
test_arr = np.random.rand(*training_data.x.shape)
# 再次测量内存
memoryUse = py.memory_info()[0] / 2. ** 30
print('memory after creating new array:', memoryUse)

如果创建新数组后内存没有明显增长,说明原数据集的内存已经被回收并复用了,只是操作系统未归还而已。

3. 排查隐藏引用问题

如果上述测试显示内存仍持续增长,那就要检查是否有隐藏引用未被释放:

  • 检查from_file方法:这个方法里有没有缓存机制?比如把加载的数组存在全局变量或类属性中?如果有,原数据集的数组会被这些缓存引用,导致无法被GC回收。
  • 检查其他引用源:有没有在日志、全局变量、回调函数等其他地方保留了training_data或test_data的引用?

4. 强制释放内存的小技巧

如果确实需要让内存归还给操作系统,可以尝试手动释放Numpy数组的内存:

def _get_data(self, data_set_name):
    training_data = DataSet.from_file('path_to_data_file','path_to_label_file')
    test_data = DataSet.from_file('path_to_data_file','path_to_label_file')
    merged_data = training_data.concat(test_data)
    # 手动删除原数据集的数组引用,强制释放内存
    del training_data.x
    del training_data.y
    del training_data
    del test_data.x
    del test_data.y
    del test_data
    gc.collect()
    return merged_data

注意:这种方法不一定能让RSS立刻下降,但能确保原数组的内存被标记为可回收。

另外,你也可以尝试从根源减少内存占用——比如直接从文件加载数据到合并后的数组中,避免创建中间数据集对象。


内容的提问来源于stack exchange,提问作者Yannic Bürgmann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:31:53