多进程中使用只读共享内存(NumPy数组)的内存增长问题排查
共享内存NumPy数组在进程池中的内存增长问题
我基于Python共享内存文档实现了一个最小示例,在进程池的工作进程调用的函数中访问基于共享内存的NumPy数组。按预期,代码的额外内存开销应该极小——只有解释器和非共享变量会产生少量开销,16GB的数组内存不会被复制。
示例代码如下:
import numpy as np from multiprocessing import Pool, shared_memory from itertools import product from tqdm import tqdm if __name__ == "__main__": a_shared_memory = shared_memory.SharedMemory(create=True, size=8_000_000_000) a = np.ndarray((20, 100, 100, 100, 100), np.float32, buffer=a_shared_memory.buf) b_shared_memory = shared_memory.SharedMemory(create=True, size=8_000_000_000) b = np.ndarray((20, 100, 100, 100, 100), np.float32, buffer=b_shared_memory.buf) def test_func(args): a[args] + b[args[:-1]] with tqdm(total=20 * 100 * 100 * 100) as pbar: with Pool(16) as pool: for _ in pool.imap_unordered(test_func, product(range(20), range(100), range(100), range(100)), chunksize=16): pass
但实际运行时,每个进程的内存占用(top命令显示的RES和SHR指标)随时间持续增长,增长速率可以通过test_func中选取的数组大小调整。
这让我很困惑:这些数组存储在共享内存中,我认为对它们的视图操作不会产生内存分配(我在Linux环境测试,仅读取操作不应触发复制)。而且我甚至没有存储计算结果,完全不清楚为什么会有内存分配。
补充两个观察:
- 有说法提到,即使读取/访问共享内存中的数组也会触发复制+写入,因为需要更新引用计数。但这应该仅影响约4KB的头内存页,为什么内存会持续增长?
- 若把代码修改为如下形式,问题就会解决——内存正常共享,没有额外开销,也不会出现持续增长的情况:
def test_func(args): a[args], b[args[:-1]]
更新:当我把test_func改为a[0, 0, 0, 0] + b[0, 0, 0]时,问题也会消失。这是不是意味着NumPy数组内部存在某种引用计数器,当访问的索引变化时会导致内存增长,而索引固定时则不会?
我希望能在test_func中执行简单计算(比如访问共享内存、加法、矩阵-向量乘法等),恳请帮助我掌握共享内存的正确使用方法。
内容的提问来源于stack exchange,提问作者Acoop
相关产品推荐
相关产品推荐

