使用pickle加载GB级文件出现MemoryError的解决方法咨询
首先得明确:你遇到的MemoryError核心原因是pickle.load()会把整个序列化对象一次性全部加载到内存中——GB级别的数据直接吃光了可用内存,哪怕是64位Python也扛不住,毕竟物理内存不是无限的。下面给你几个实用的解决思路,按优先级排序:
1. 用Joblib替代Pickle(优先推荐)
如果你的文件是机器学习模型(比如scikit-learn模型)或者包含大numpy数组,joblib是专门为这类场景优化的工具,它支持分块存储和内存映射加载,能大幅降低内存占用。
加载示例(替换你的原代码):
import joblib import os model_file_path = os.path.join(model_directory, model_file_name) # 使用mmap_mode='r'将数据映射到磁盘,而非全部加载到内存 return joblib.load(model_file_path, mmap_mode='r')
如果是你自己保存的模型,下次保存时也改用joblib,效果更好:
joblib.dump(your_model, model_file_path, compress=3) # compress参数可选,平衡存储大小和速度
2. 分块反序列化(适用于分块保存的对象)
如果当初保存这个大对象时是分多次调用pickle.dump()的,那加载时可以用pickle.Unpickler逐块读取,避免一次性加载全部内容:
import pickle import os model_file_path = os.path.join(model_directory, model_file_name) with open(model_file_path, 'rb') as fh: unpickler = pickle.Unpickler(fh) # 假设对象由3个部分组成,逐块加载后再组合 part1 = unpickler.load() part2 = unpickler.load() part3 = unpickler.load() full_model = combine_parts(part1, part2, part3) # 这里需要你自己实现组合逻辑 return full_model
⚠️ 注意:如果原文件是一次性用pickle.dump()保存的,这个方法不适用,因为pickle会把整个对象打包成一个块。
3. 启用内存映射或虚拟内存
内存映射(配合Joblib)
上面Joblib示例中的mmap_mode='r'就是内存映射,它让系统把文件内容当作内存的一部分,只有访问到的部分才会加载到物理内存,适合只读场景。
虚拟内存(Swap空间)
如果暂时没法改代码,可以通过系统层面增加虚拟内存(把磁盘空间当内存用)来缓解。比如:
- Linux:创建swap文件并启用
- Windows:右键"此电脑"→属性→高级系统设置→性能→设置→高级→虚拟内存→更改
不过这个方法会减慢程序运行速度,只是临时应急方案。
4. 拆分大对象(从根源解决)
如果这个大模型是你自己构建的,考虑把它拆分成多个独立的子组件,分别保存为多个小文件。加载时逐个读取子组件,再组装成完整模型。比如把模型的权重、配置、特征分别存成不同的pickle/joblib文件,按需加载。
5. 尝试用Dill替代Pickle
Dill是Pickle的扩展,支持更多Python对象类型,在某些场景下内存管理更高效。可以试试替换Pickle为Dill:
import dill import os model_file_path = os.path.join(model_directory, model_file_name) with open(model_file_path, 'rb') as fh: return dill.load(fh)
不过这个方法不一定能解决GB级的内存问题,但作为备选方案值得一试。
内容的提问来源于stack exchange,提问作者Qingqing_L

