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

为何加载为字典的数据内存开销是磁盘中相同数据的两倍?

为什么Python加载JSON后内存开销是磁盘的两倍?

这事儿我之前处理超大JSON数据集的时候踩过一模一样的坑,明明磁盘上才60GB,加载到Python里直接飙到110GB+,其实核心原因是JSON文本格式和Python内存中对象的存储逻辑完全不在一个维度上,具体拆解下来有这么几个关键点:

1. Python对象的固有内存开销

Python里的每一个基础对象(dict、list、int、float甚至字符串)都不是“裸数据”,而是带有额外管理信息的结构体:

  • 一个空的dict在64位系统上就占约40字节(包含引用计数、类型指针、哈希表元数据等),空list也差不多是这个大小;
  • 哪怕是一个整数,小整数虽然有全局 intern 缓存,但如果是大量不重复的大整数,每个int对象要占28字节(64位);浮点数更甚,每个float对象占24字节;
  • 嵌套结构的开销更是翻倍:比如一个嵌套的dict,每一层都要额外占用哈希表的内存,而JSON文件里只是用{}和:来表示结构,没有这些额外的元数据。

对比下来,磁盘上的JSON是纯文本紧凑存储,比如一个整数"12345"只占5字节,加载成Python的int后直接膨胀到28字节,差距一下子就拉开了。

2. JSON文本的天然紧凑性

JSON作为文本格式,本身就比内存中的对象结构紧凑:

  • 重复的键名在JSON里是重复的字符串,但加载到Python中,虽然字符串会被 intern 缓存,但如果是大量不同的长键名,每个键都要占用独立的内存空间;
  • 数组和对象的结构在JSON里只用少量符号([]、{}、,)表示,而Python的list需要存储每个元素的指针(64位系统每个指针8字节),光是指针的开销就占了很大一部分。

举个例子:一个包含1000个整数的列表,JSON里的文本可能只占几千字节,但加载成Python的list后,光是1000个指针就占8000字节,再加上每个整数的28字节,总开销直接飙到36000字节,是磁盘大小的好几倍。

3. 内存对齐与碎片问题

操作系统和Python的内存管理器都是按固定大小的块来分配内存的(比如内存页),这就会导致内存碎片:

  • 大量小对象分配后,会留下很多无法被利用的小内存块,整体内存使用率降低,看起来就像是“用了更多内存”;
  • 比如你有一堆大小不一的嵌套dict,Python为每个dict分配的内存块会比实际需要的略大,日积月累下来,额外的开销就很可观了。

4. 加载过程中的临时对象(峰值开销)

虽然你说的是加载完成后的内存占用,但加载过程中JSON库(比如标准库的json.load)会创建大量临时对象,这些对象虽然最后会被GC回收,但加载峰值时的内存占用可能比最终的内存占用还要高,不过这部分通常不会留存太久。


一些优化建议

如果想降低内存开销,可以试试这些方法:

  • 换用二进制序列化格式:比如MessagePack、Parquet或者Feather,这些格式是二进制的,磁盘存储更紧凑,加载到内存后的对象开销也远低于JSON;
  • 用Pandas加载:pandas.read_json会把相同键的列转换成数组存储,避免了每个dict重复存储键名的开销,内存占用会大幅降低;
  • 用自定义类替代dict:比如用@dataclass或者__slots__定义数据类,替代原生的dict,可以减少每个对象的内存开销(dict的哈希表开销很大,自定义类可以省去这部分);
  • 逐行加载(如果适用):如果你的JSON是每行一个对象的格式,可以用生成器逐行处理,不用一次性把所有数据载入内存,但这只适合不需要全量数据在内存的场景。

内容的提问来源于stack exchange,提问作者vaer-k

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:09:39