加载JSON文件时出现MemoryError

Aga*_*'lo 4 python memory json

当我加载500Mo大的JSON文件时,Python(和spyder)返回MemoryError.

但我的电脑有一个32Go内存,当我试图加载时,spyder显示的"内存"从15%到19%!看来我应该有更多的空间......

我没想到的东西?

Mar*_*ers 8

500MB的JSON数据不会导致500MB的内存使用量.它将导致其中的多个.究竟是什么因素取决于数据,但10-25的因素并不罕见.

例如,以下14个字符的简单JSON字符串(磁盘上的字节)导致Python对象几乎大25倍(Python 3.6b3):

>>> import json
>>> from sys import getsizeof
>>> j = '{"foo": "bar"}'
>>> len(j)
14
>>> p = json.loads(j)
>>> getsizeof(p) + sum(getsizeof(k) + getsizeof(v) for k, v in p.items())
344
>>> 344 / 14
24.571428571428573
Run Code Online (Sandbox Code Playgroud)

那是因为Python对象需要一些开销; 实例跟踪对它们的引用数,它们是什么类型,它们的属性(如果类型支持属性)或它们的内容(在容器的情况下).

如果您使用json内置库来加载该文件,则必须在解析内容时从内容构建越来越大的对象,并且在某些时候您的操作系统将拒绝提供更多内存.这不会是32GB,因为每个进程有一个限制可以使用多少内存,所以更有可能是4GB.此时,所有已创建的对象都会被再次释放,因此最终实际的内存使用不必发生太大变化.

解决方案是将大型JSON文件拆分为更小的子集,或者使用事件驱动的JSON解析器ijson.

事件驱动的JSON解析器不会为整个文件创建Python对象,仅针对当前解析的项目,并通过事件通知您的代码创建的每个项目(例如'开始一个数组,这里是一个字符串,现在开始映射,这是映射的结束等).然后,您可以决定需要和保留哪些数据,以及忽略哪些数据.您忽略的任何内容都会被再次丢弃,内存使用率会保持较低.