You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 09:33:02