我编写了一个python脚本,它读取了两个文件的内容,第一个是相对较小的文件(~30KB),第二个是较大的文件~270MB。两个文件的内容都加载到字典数据结构中。当第二个文件被加载时,我原本预计所需的RAM量大致相当于磁盘上文件的大小,可能有一些开销,但是看着我的PC上的RAM使用量似乎一直需要~2GB(左右)文件大小的8倍)。相关的源代码如下(暂停插入,以便我可以看到每个阶段的RAM使用情况)。消耗大量内存的行是“tweets = map(json.loads,tweet_file)”:
def get_scores(term_file):
global scores
for line in term_file:
term, score = line.split("\t") #tab character
scores[term] = int(score)
def pause():
tmp = raw_input('press any key to continue: ')
def main():
# get terms and their scores..
print 'open word list file ...'
term_file = open(sys.argv[1])
pause()
print 'create dictionary from word list file ...'
get_scores(term_file)
pause()
print 'close word list file ...'
term_file.close
pause()
# get tweets from file...
print 'open tweets file ...'
tweet_file = open(sys.argv[2])
pause()
print 'create dictionary from word list file ...'
tweets = map(json.loads, tweet_file) #creates a list of dictionaries (one per tweet)
pause()
print 'close tweets file ...'
tweet_file.close
pause()
有谁知道这是为什么?我担心的是,我想将我的研究扩展到更大的文件,但会快速耗尽内存。有趣的是,打开文件后内存使用量似乎没有明显增加(因为我认为这只是创建一个指针)。
我有一个想法,一次尝试循环遍历文件并处理我能做的事情,只存储我需要的最小值以供将来参考,而不是将所有内容加载到字典列表中,但我只是对看看创建字典时文件大小乘以8倍的内存是否符合其他人的经验?
答案 0 :(得分:2)
我猜测你的词典中有多个副本同时存储在内存中(各种格式)。例如,行:
tweets = map(json.loads, tweet_file) #creates a list of dictionaries (one per tweet)
将创建一个 new 副本(+ 400~1000MB包含字典的开销)。但你原来的tweet_file
留在记忆中。为什么这么大的数字?好吧,如果你使用Unicode字符串,每个Unicode字符在内存中使用2或4个字节。而在您的文件中,假设UTF-8编码,大多数字符只使用1个字节。如果在Python 2中使用普通字符串,则内存中字符串的大小应与磁盘上的大小几乎相同。所以你必须找到另一种解释。
编辑: Python 2中“字符”占用的实际字节数可能会有所不同。以下是一些例子:
>>> import sys
>>> sys.getsizeof("")
40
>>> sys.getsizeof("a")
41
>>> sys.getsizeof("ab")
42
如您所见,出现,每个字符都编码为一个字节。但是:
>>> sys.getsizeof("à")
42
不适用于“法国”字符。而且......
>>> sys.getsizeof("世")
43
>>> sys.getsizeof("世界")
46
对于日语,我们每个字符有3个字节。
以上结果取决于网站 - 并且我的系统使用'UTF-8'作为默认编码。上面计算的“字符串大小”实际上是“字节字符串的大小”表示给定文本。
如果'json.load'使用“unicode”字符串,结果会有所不同:
>>> sys.getsizeof(u"")
52
>>> sys.getsizeof(u"a")
56
>>> sys.getsizeof(u"ab")
60
>>> sys.getsizeof(u"世")
56
>>> sys.getsizeof(u"世界")
60
在这种情况下,正如您所看到的,每个额外的字符都会增加4个字节。
也许文件对象会缓存一些数据?如果要触发对象的显式dellaocation,请尝试将其引用设置为None:
tweets = map(json.loads, tweet_file) #creates a list of dictionaries (one per tweet)
[...]
tweet_file.close()
tweet_file = None
当对某个对象没有任何引用时,Python会解除它 - 然后释放相应的内存(来自Python堆的 - 我不认为是内存返回系统)。
答案 1 :(得分:1)
我写了一个快速测试脚本来确认你的结果......
import sys
import os
import json
import resource
def get_rss():
return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss * 1024
def getsizeof_r(obj):
total = 0
if isinstance(obj, list):
for i in obj:
total += getsizeof_r(i)
elif isinstance(obj, dict):
for k, v in obj.iteritems():
total += getsizeof_r(k) + getsizeof_r(v)
else:
total += sys.getsizeof(obj)
return total
def main():
start_rss = get_rss()
filename = 'foo'
f = open(filename, 'r')
l = map(json.loads, f)
f.close()
end_rss = get_rss()
print 'File size is: %d' % os.path.getsize(filename)
print 'Data size is: %d' % getsizeof_r(l)
print 'RSS delta is: %d' % (end_rss - start_rss)
if __name__ == '__main__':
main()
...打印......
File size is: 1060864
Data size is: 4313088
RSS delta is: 4722688
...所以我只增加了四倍,这可以通过每个Unicode字符占用四个字节的RAM这一事实来解释。
也许您可以使用此脚本测试输入文件,因为我无法解释为什么您的脚本会增加八倍。
答案 2 :(得分:0)
您是否考虑过密钥的内存使用情况?如果字典中有许多小值,则键的存储可能占主导地位。