Python批量拆分JSON为单对象文件时内存不足问题问询
JSON拆分脚本内存不足优化方案
核心问题分析
你当前脚本内存占用过高的根本原因是使用json.load()将整个JSON文件的所有对象一次性全量加载到内存中生成docs列表,当批量处理大文件时,内存会被大量未释放的对象占满,最终触发内存不足。
可行优化方案
1. 替换为流式JSON解析(最有效)
放弃全量加载的内置json模块,改用ijson第三方库,它会边读取文件边解析,仅加载当前正在处理的单个对象到内存,内存占用可以稳定在KB级别,和文件总大小无关。
安装命令:pip install ijson
2. 优化现有代码冗余逻辑
- 废弃Python2专属的
commands模块,改用文件锁实现单实例运行,比调用ps/grep/wc的外部命令组合更稳定高效,也避免额外的进程开销 - 路径拼接改用
os.path.join(),避免手动拼接路径的格式错误 - Python3.7及以上版本默认dict已经支持插入顺序保留,可以去掉
OrderedDict的依赖,减少不必要的对象开销 - 处理完单个文件后及时释放所有关联的文件对象引用,避免内存泄漏
3. 附加优化建议
- 如果你的原始JSON是每行一个对象的JSON Lines格式,可以直接逐行读取解析,不需要引入第三方库,性能更高
- 可以限制单次处理的文件数量,处理完一批就等待内存释放后再处理下一批,避免同时堆积过多待处理对象
优化后参考代码
#!/usr/bin/python3 import os import json import shutil import ijson import fcntl # 用文件锁实现单实例运行,逻辑更可靠 lock_file = "/tmp/splitjson.lock" lock_fp = open(lock_file, 'w') try: fcntl.lockf(lock_fp, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError: print("已有正在运行的拆分进程,退出") exit(0) # 路径配置 base_path = '/home/subhome/json2/' dest_path = '/home/subhome/jskaf/' err_path = '/home/subhome/jskaf/err/' archive_path = '/home/subhome/jskaf/arch/' # 预创建目标目录避免运行时报错 for p in [dest_path, err_path, archive_path]: if not os.path.exists(p): os.makedirs(p) # 遍历处理文件 for filename in os.listdir(base_path): if not filename.endswith('.json'): continue file_prefix = filename.rsplit('.json', 1)[0] src_file = os.path.join(base_path, filename) dest_file_prefix = os.path.join(dest_path, file_prefix) err_file = os.path.join(err_path, filename) archive_file = os.path.join(archive_path, filename) print(f"正在处理:{src_file}") try: with open(src_file, 'rb') as f: # 流式解析JSON数组,每次仅加载一个对象到内存 for idx, doc in enumerate(ijson.items(f, 'item')): output_path = f"{dest_file_prefix}.{idx}.json" with open(output_path, 'w', encoding='utf-8') as out_f: json.dump(doc, out_f, indent=2, ensure_ascii=False) # 处理完成归档原文件 shutil.move(src_file, archive_file) except Exception as e: print(f"处理文件{src_file}失败:{str(e)}") shutil.move(src_file, err_file)
内容的提问来源于stack exchange,提问作者Raj
相关产品推荐
相关产品推荐

