Pie*_*nne 14 python memory file-io large-files
我在Python中打开一个3 GB的文件来读取字符串.然后我将这些数据存储在字典中.我的下一个目标是使用这个字典构建一个图形,所以我正在密切监视内存使用情况.
在我看来,Python将整个3 GB文件加载到内存中,我无法摆脱它.我的代码看起来像这样:
with open(filename) as data:
accounts = dict()
for line in data:
username = line.split()[1]
IP = line.split()[0]
try:
accounts[username].add(IP)
except KeyError:
accounts[username] = set()
accounts[username].add(IP)
print "The accounts will be deleted from memory in 5 seconds"
time.sleep(5)
accounts.clear()
print "The accounts have been deleted from memory"
time.sleep(5)
print "End of script"
Run Code Online (Sandbox Code Playgroud)
最后一行是在那里,以便我可以监视内存使用情况.该脚本在内存中使用超过3 GB的位.清除字典可以释放大约300 MB.当脚本结束时,释放剩余的内存.
我正在使用Ubuntu,我使用"系统监视器"和终端中的"免费"命令监视内存使用情况.
我不明白的是为什么在我清除字典之后Python需要这么多内存.文件是否仍存储在内存中?如果是这样,我怎么能摆脱它呢?我的操作系统没有看到释放内存的问题吗?
编辑:我已经尝试在清除字典后强行执行gc.collect(),但无济于事.
EDIT2:我在Ubuntu 12.04.LTS上运行Python 2.7.3
EDIT3:我意识到我忘了提到一些非常重要的东西.我真正的问题不在于我的操作系统没有"取回"Python使用的内存.后来,Python似乎没有重用那个内存(它只是要求操作系统有更多的内存).
Jon*_*sco 13
这对我来说确实没有意义,我想弄清楚这是怎么回事.(我认为这也应该如何工作!)我在我的机器上复制它 - 虽然文件较小.
我在这看到两个不连续的问题
我对Python内部结构一点也不了解,所以我只是进行了大量的网络搜索.所有这些都可能完全不合适.(我几乎没有发展,过去几年一直在科技的商业方面)
我环顾四周,找到了这篇文章 -
http://www.peterbe.com/plog/blogitem-040312-1
它来自python的早期版本,但这条线路与我共鸣:
readlines()立即读入整个文件并按行拆分.
然后我看到了这个,也是旧的,effbot帖子:
http://effbot.org/zone/readline-performance.htm
关键的一点是:
例如,如果您有足够的内存,则可以使用readlines方法将整个文件粘贴到内存中.
还有这个:
在Python 2.2及更高版本中,您可以遍历文件对象本身.这与封面上的readlines(N)非常相似,但看起来要好得多
查看用于xreadlines的pythons docs [ http://docs.python.org/library/stdtypes.html?highlight=readline#file.xreadlines ]:
此方法返回与iter相同的内容(f)从版本2.3开始不推荐使用:用于替换文件.
它让我觉得也许正在进行一些诽谤.
所以如果我们看一下readlines [ http://docs.python.org/library/stdtypes.html?highlight=readline#file.readlines ] ......
使用readline()读取EOF并返回包含如此读取的行的列表.
这看起来就像是在这里发生的事情.
然而,readline看起来像我们想要的[ http://docs.python.org/library/stdtypes.html?highlight=readline#file.readline ]
从文件中读取整行
所以我尝试将其切换到readline,并且该过程从未超过40MB(它增长到200MB,日志文件的大小,之前)
accounts = dict()
data= open(filename)
for line in data.readline():
info = line.split("LOG:")
if len(info) == 2 :
( a , b ) = info
try:
accounts[a].add(True)
except KeyError:
accounts[a] = set()
accounts[a].add(True)
Run Code Online (Sandbox Code Playgroud)
我的猜测是,我们并不是真的懒得用结构读取文件for x in data- 尽管所有的文档和stackoverflow评论都表明我们是. readline()为我消耗的内存显着减少,并realdlines消耗了大约相同的内存量for line in data
在释放内存方面,我对Python的内部结构并不熟悉,但我回想起当我使用mod_perl时......如果我打开了一个500MB的文件,那个apache的孩子就会变得那么大.如果我释放了内存,它只会在那个孩子中自由 - 垃圾收集的内存从未返回到操作系统,直到进程退出.
所以我讨论了这个想法,发现了一些暗示这可能发生的链接:
http://effbot.org/pyfaq/why-doesnt-python-release-the-memory-when-i-delete-a-large-object.htm
如果你创建一个大对象并再次删除它,Python可能已经释放了内存,但所涉及的内存分配器不一定会将内存返回给操作系统,所以看起来好像Python进程使用了更多的虚拟内存而不是它实际使用.
这有点旧了,之后我发现了一堆随机(接受)补丁到python中,表明行为已经改变了,你现在可以将内存返回给操作系统了(截至2005年,当大多数补丁被提交并且显然被批准时) ).
然后我发现这个帖子http://objectmix.com/python/17293-python-memory-handling.html - 并注意到评论#4
"" - 补丁#1123430:Python的小对象分配器现在在竞技场中的
free()所有内存再次未使用时返回系统的竞技场.在Python 2.5之前,竞技场(256KB内存块)从未被释放.有些应用程序会看到现在虚拟内存大小下降,特别是长时间运行的应用程序,有时会临时使用大量小对象.请注意,当Python返回平台C的竞技场时free(),无法保证平台C库将会反过来将该内存返回给操作系统.补丁的作用是停止使这不可能,并且在测试中它至少在Microsoft C和基于gcc的系统上似乎是有效的.感谢Evan Jones的辛勤工作和耐心.因此,在Linux下使用2.4(正如您测试的那样),对于收集的大量小对象,您确实不会总是得到用过的内存.
因此(我认为)在执行f.read()和f.readlines()之间的区别在于前者将整个文件作为一个大字符串对象(即不是小对象)读取,而后者返回每行都是python对象的行列表.
如果'for line in data:'构造实际上是包装readlines而不是readline,那么这可能与它有关吗?也许这不是一个3GB对象的问题,而是拥有数百万个30k对象.