Python:如何进行字符串垃圾回收
我在一个运行时间很长的脚本中遇到了问题。这个脚本是在多线程环境下运行的,用来执行爬虫任务。
在执行很大的任务时,脚本的内存消耗变得非常高。通过使用guppy hpy工具分析内存后,我发现大部分问题都是由字符串引起的。
我并没有存储很多字符串:只是把HTML的内容加载到内存中,然后存入数据库。之后,这些字符串就不再使用了(包含它的变量会被赋值为下一个字符串)。
问题出现是因为我发现每个新字符串(通过sys.getrefcount查看)至少有两个引用(一个是我的变量,另一个是内部引用)。看起来,当我把变量重新赋值为其他值时,并没有删除内部引用,所以字符串仍然留在内存中。
我该怎么做才能确保字符串被垃圾回收?
谢谢你的帮助
编辑:
1- 我在使用Django的ORM
2- 我从两个来源获取这些字符串:
2.1- 直接从socket获取(urllib2.urlopen(url).read())
2.2- 解析这些响应,从每个HTML中提取新的URI,并将其提供给系统
解决了
最后,我找到了关键。这个脚本是Django环境的一部分,似乎Django的底层在做一些缓存或类似的事情。我关闭了调试模式,一切开始按预期工作(重用标识符似乎删除了对旧对象的引用,这些对象就被垃圾回收了)。
对于使用某种框架层的Python用户,要注意配置:一些调试配置在进行大量处理时可能会导致内存泄漏。
2 个回答
你需要找出是谁在“内部”保存了你的字符串引用。可能是你用来写入数据库的库(你没有说明你是怎么写入数据库的)。我发现 objgraph 在处理这种任务时非常有用:https://pypi.python.org/pypi/objgraph
例如:
import objgraph
objgraph.show_backrefs([mystring], filename='a.png')
你说:
我发现每个新字符串(用sys.getrefcount)至少有两个引用
但是你有没有仔细看过getrefcount()
的说明呢?:
sys.getrefcount()
这个函数会返回对象的引用计数。返回的计数通常比你预期的要多1,因为它还包括了作为参数传给getrefcount()的(临时)引用。
。
你应该多解释一下你的程序。
它所持有的HTML字符串大小是多少?
这些字符串是怎么获得的?你确定关闭了所有文件的句柄、所有的套接字连接吗……?