NumPy中np.ones疑似内存泄漏?相关测试现象及原因问询
现象原因解答
核心结论
这个现象不是NumPy内存泄漏,是内存分配器缓存策略和memory_profiler统计逻辑共同导致的假象。
具体原因拆解
- 临时数组的分配逻辑差异
你编写的arr[0:75,:] = np.ones((75, 6912))执行时,会先创建一个大小约为3.9MiB的临时数组(7569128字节,对应NumPy默认float64类型),赋值完成后这个临时对象就失去引用,符合回收条件。
而替换为arr[0:75,:] = 1时,NumPy会直接通过广播机制原地修改目标数组的值,不需要创建临时数组,所以不会触发额外的内存分配,自然就没有对应的内存增长。 - 内存分配器的缓存机制
C标准库(如Ubuntu下的glibc ptmalloc)为了提升内存分配效率,进程释放的内存不会立刻归还给操作系统,而是会留存在进程的本地内存池中,供后续同规格的内存申请复用。你循环2000次创建同大小的临时数组,只会在第一次申请时向操作系统索要3.9MiB内存,后续1999次都是复用内存池中的空间,不会再新增进程内存占用,所以你看到的总增量只有3.9MiB,不会随循环次数线性增长,完全不符合内存泄漏的特征。 memory_profiler的统计特性memory_profiler统计的是进程向操作系统申请的总内存变化,不是某行代码的净内存增减。那3.9MiB是内存分配器留存的缓存,不是泄漏的内存,后续程序再有同大小的内存申请时会直接复用这部分空间,不会额外占用内存。
验证方法
你可以做两个简单测试确认没有泄漏:
- 把循环次数从2000改成20000再运行,你会发现第9行的总增量依然是3.9MiB左右,不会线性上涨
- 在
gc.collect()之后再添加一行tmp = np.ones((75, 6912)),你会看到进程内存不会再增长,说明是直接复用了之前缓存的内存
内容的提问来源于stack exchange,提问作者Alex Reinking
相关产品推荐
相关产品推荐

