Python 2.7 Python-不同的对象创建方法-内存分配

Python 2.7 Python-不同的对象创建方法-内存分配,python-2.7,memory-management,Python 2.7,Memory Management,关于反序列化,我得到了一个很好的答案,这使我创建了一个方法,该方法要么反序列化文件中的defaultdict(list),要么在文件不存在时创建字典本身 在实现了一个简单的代码之后 try: #deserialize - this takes about 6 seconds with open('dict.flat') as stream: for line in stream: vals = line.split()

关于反序列化,我得到了一个很好的答案,这使我创建了一个方法,该方法要么反序列化文件中的
defaultdict(list)
,要么在文件不存在时创建字典本身

在实现了一个简单的代码之后

try:
    #deserialize - this takes about 6 seconds
    with open('dict.flat') as stream:
        for line in stream:
            vals = line.split()
            lexicon[vals[0]] = vals[1:]
except:
    #create new - this takes about 40 seconds
    for word in lexicon_file:
        word = word.lower()
            for letter n-gram in word:
                lexicon[n-gram].append(word)
    #serialize - about 6 seconds
    with open('dict.flat', 'w') as stream:
        stream.write('\n'.join([' '.join([k] + v) for k, v in lexicon.iteritems()]))
当从文件反序列化时,我的脚本占用的RAM量让我有点震惊

(lexicon_文件包含约620000个单词,处理后的
defaultdict(list)
包含25000个键,而每个键包含1到133000个字符串(平均500个,中位数20个)。 每个键都是一个字母bi/trigram,其值是包含键字母n-gram的单词。)

当脚本重新创建词典时,整个过程使用的内存不会超过160 MB——序列化文件本身略超过129 MB。 当脚本对词典进行反序列化时,python.exe占用的RAM量会跃升到500 MB

当我尝试在反序列化过程中使用

#deserialize one by one - about 15 seconds
with open('dict.flat') as stream:
    for line in stream:
        vals = line.split()
        for item in vals[1:]:
            lexicon[vals[0]].append(item)
结果完全相同-除了此代码段运行速度明显较慢之外

是什么导致内存消耗如此巨大的差异?我的第一个想法是,由于结果列表中的许多元素完全相同,python以某种方式通过引用更有效地创建了字典,这在反序列化整个列表并将其映射到键时是没有时间的。但是如果是这样的话,为什么这个问题不能通过一个接一个地添加条目来解决,就像创建一个新的词典一样

编辑:这个话题已经在(我怎么会错过它?!)中讨论过了。通过使用
intern()
函数,可以强制Python从引用创建字典:

#deserialize with intern - 45 seconds
with open('dict.flat') as stream:
    for line in stream:
        vals = line.split()
        for item in vals[1:]:
            lexicon[intern(vals[0])].append(intern(item))

这会将字典占用的RAM量减少到预期值(160 MB),但偏移量是计算时间恢复到与重新创建dict相同的值,这完全否定了序列化的原因。

是否考虑过文件对象可能仍在内存中(或者,更确切地说,Python可能不会释放内存)?你是如何检查内存使用情况的?它会随着时间的推移而下降吗?@jornsharpe我尝试了几种内存分析方法,但最终他们都通过python.exe检查了完整的内存使用情况。我不相信内存是免费的,只是由python保留以供进一步使用,因为脚本的其余部分会在上增加更多内存使用在这个结构的顶部,甚至在调用GC之后(脚本的其余部分需要大约50MB的RAM)。您可以使用,例如,逐行查看使用情况。我已经使用了它,但它只计算循环的最终内存使用情况,而不提供进一步的统计信息,如每个循环的内存等。由于我正在创建一个列表目录,所以我不能不使用循环进行反序列化。