Python中删除对象后内存无法回收的问题求助
删除numpy数组引用后内存未释放的异常问题
开发过程中,将对象临时存储在列表中,删除对象的所有引用后发现内存仍未释放,导致进程RAM占用过高。复现了一个简单示例,结果不符合预期,代码如下:
import psutil import os import gc import sys import numpy as np mod = int(sys.argv[1]) process = psutil.Process(os.getpid()) print(f"Empty memory: {process.memory_info().rss/1e6:.1f}MB") arrs = list() for i in range(1000): arr = np.arange(50000) * i if i % mod == 0: arrs.append(arr) print(f"Memory before cleaning: {process.memory_info().rss/1e6:.1f}MB - {len(arrs)} elements in array") del arrs gc.collect() print(f"Memory after cleaning: {process.memory_info().rss/1e6:.1f}MB")
使用不同参数运行后的结果:
# 1 Empty memory: 33.3MB Memory before cleaning: 435.4MB - 1000 elements in array Memory after cleaning: 34.4MB #2 Empty memory: 33.3MB Memory before cleaning: 234.2MB - 500 elements in array Memory after cleaning: 34.5MB #3 - 为何此场景下内存未被回收? Empty memory: 33.3MB Memory before cleaning: 167.8MB - 334 elements in array Memory after cleaning: 167.8MB #500 Empty memory: 33.3MB Memory before cleaning: 35.4MB - 2 elements in array Memory after cleaning: 34.4MB
疑问
完全不符合预期:为何mod=3时内存未回收?为何数组规模越大内存回收越彻底?
解答
这是numpy底层内存分配器的缓存策略导致的,和Python垃圾回收机制无关:
- numpy依赖系统级内存分配器(比如Linux下的glibc ptmalloc、Windows下的HeapAlloc)管理内存。释放内存时,分配器不会立刻把所有内存还给操作系统——尤其是小内存块,会被缓存到进程内存池中,供后续内存申请复用,避免频繁向操作系统申请/释放内存的性能开销。
- 具体到测试用例:
- mod=1/2时,数组总数量多,每个数组属于较大内存块(单个数组为50000个int64,约390KB)。释放这些大块内存时,分配器判断暂时无复用需求,就会把内存归还给操作系统,因此rss(驻留内存)明显下降。
- mod=3时,334个数组的总内存约130MB,每个都是400KB级别的小内存块。释放后,分配器将这些内存留在进程缓存池中,不会立刻归还操作系统,所以rss数值看起来无变化。但这些内存可被后续numpy或其他代码复用——你可以尝试在
gc.collect()后再创建一批同样大小的数组,会发现内存不再增长,因为复用了缓存的内存。 - mod=500时仅2个数组,总内存很小,释放后分配器可轻松将小内存块归还给操作系统,因此rss回到初始水平。
另外要注意,rss(Resident Set Size)统计的是进程实际占用的物理内存,包含了分配器缓存的未使用内存。如果想查看程序真正在使用的内存,可以关注numpy内部的内存使用,或者用vms(虚拟内存大小)辅助判断,但vms包含已申请但未使用的虚拟地址空间,参考价值有限。
内存分配器的行为会因操作系统、分配器实现不同而变化,但核心逻辑都是缓存小内存块以提升性能。
内容的提问来源于stack exchange,提问作者RobinFrcd
相关产品推荐
相关产品推荐

