为什么数据字典的内存开销是磁盘上相同数据的两倍



我正在尝试从包含大约300万个JSON序列化对象的文件中加载数据集。每个对象都是一个大型嵌套词典,其中包含多种类型 - int,浮子,列表和其他字典。

磁盘上文件的大小约为60gb。我有超过128GB的RAM,因此我应该能够将整个集合适合内存。但是,当我使用以下代码将数据加载到大型字典中时,用过的内存的大小将至少增加到110GB(甚至可能会变大,但是我在脚本增长之前就停止了。(

(

当我尝试加载这些数据时,我可以解释我看到的内存开销?为什么磁盘上的60GB在内存中会转换为110GB或更多?据我所知,这里唯一的开销应该是为对象创建列表容器的结果,并在结果字典中为这些列表分配一个关键名称。这可能无法说明数据本身几乎两倍 - 可以吗?

def load_by_geohash(file, specificity=7):
    results = defaultdict(list)
    filename = os.path.join(DATADIR, file)
    with open(filename, 'r') as f:
        updates = (json.loads(line) for line in f)
        for update in updates:
            geo_hash = update['geohash'][:specificity]
            results[geo_hash].append(update)
    return results

是的,很容易。考虑一个简单的字符串列表:

>>> import json
>>> from sys import getsizeof
>>> x = ['a string', 'another string', 'yet another']
>>> sum(map(getsizeof, x)) + getsizeof(x)
268
>>> len(json.dumps(x).encode())
45
>>>

在Python中,一切都是对象。因此,每个(嗯,大多数(单个对象至少都有至少 sys.getsizeof(object())开销。注意,我的系统上的一个空字符串:

>>> getsizeof('')
49

注意,对于dict对象,此差异更大,请考虑:

>>> d
{'a': 'a string', 'b': 'another string', 'c': 'yet another'}
>>> sum(map(getsizeof, d)) + sum(map(getsizeof, d.values())) + getsizeof(d)
570
>>> len(json.dumps(d).encode())
60

对于空的dict来说,这是巨大的:

>>> getsizeof({}), len(json.dumps({}).encode())
(240, 2)

现在,有多种选择可以更紧凑地存储数据。但这取决于您的用例。

这是关于许多字典的记忆使用情况的相关问题。还有一个使用numpy数组和namedtuple对象更紧凑的数据的示例。注意,使用namedtuple对象可能是您需要的,内存节省可能是巨大的,因为您不需要为键存储实际的字符串对象。如果您的量词结构是常规的,我建议用嵌套的namedtuple对象替换那些嵌套的update dict。

最新更新