np.memmap可实现磁盘级分页,按需加载数据块以避免内存溢出;需显式指定dtype、shape等参数对齐字节偏移,并配合分块迭代、合适数据类型与内存布局及生成器优化内存使用。

用 np.memmap 实现磁盘级分页
当数组远超可用内存(比如 20GB 的 .npy 文件),np.memmap 是最直接的“分页”方案。它不把数据加载进 RAM,而是让操作系统按需从磁盘读取字节块——访问某一行时才触发对应磁盘 IO,内存占用几乎为零。关键是要严格指定 filename、dtype、mode 和 shape,因为 memmap 不解析文件头,全靠你提供的参数对齐字节偏移。例如:
- 写入:
mmap = np.memmap('data.dat', dtype=np.float32, mode='w+', shape=(1e6, 1000)) - 读取:
mmap = np.memmap('data.dat', dtype=np.float32, mode='r', shape=(1e6, 1000)) - 切片访问:
mmap[10000:10100, :]只加载这 100 行,其余不动
手动分块迭代处理
对 memmap 或已加载的大型数组做计算时,不能直接调用 .sum() 或 .groupby() 等全局操作,否则仍会触发内存爆炸。应主动按维度切分,逐块处理再合并结果。常见模式是沿行或列方向滑动窗口:
- 按行分块:每批处理
block_size=5000行,for i in range(0, arr.shape[0], block_size): chunk = arr[i:i+block_size] - 按列分块(适合列操作):适用于归一化、PCA 等列向算法,避免整行加载
- 二维分块(如图像/矩阵运算):
arr[i:i+h, j:j+w],控制 h 和 w 使单块内存可控
选择合适的数据类型与布局
内存压力不仅来自尺寸,还来自每个元素的字节开销和访问效率。同一数组,float32 比 float64 节省一半空间;int8 在满足精度前提下可压到 1/4。同时注意内存布局:
- C-order(默认)更适合按行遍历,按行分块时缓存命中率高
- F-order 更适合按列密集操作,若频繁取
arr[:, j],用order='F'创建能减少内存跳转 - 用
arr.flags.c_contiguous或f_contiguous检查当前布局是否匹配你的访问模式
结合生成器释放中间内存
在流水线式处理中(如向量相似度计算、特征提取),用生成器替代列表累积,可避免临时结果堆积。例如:
- 不用
results = [process(chunk) for chunk in chunks](全部存内存) - 改用
def process_chunks(chunks): for chunk in chunks: yield process(chunk),再用itertools.chain或逐个 consume - 配合
del chunk显式释放引用,加速垃圾回收











