Python:如何进行字符串垃圾回收

2 投票
2 回答
2053 浏览
提问于 2025-04-17 17:34

我在一个运行时间很长的脚本中遇到了问题。这个脚本是在多线程环境下运行的,用来执行爬虫任务。

在执行很大的任务时,脚本的内存消耗变得非常高。通过使用guppy hpy工具分析内存后,我发现大部分问题都是由字符串引起的。

我并没有存储很多字符串:只是把HTML的内容加载到内存中,然后存入数据库。之后,这些字符串就不再使用了(包含它的变量会被赋值为下一个字符串)。

问题出现是因为我发现每个新字符串(通过sys.getrefcount查看)至少有两个引用(一个是我的变量,另一个是内部引用)。看起来,当我把变量重新赋值为其他值时,并没有删除内部引用,所以字符串仍然留在内存中。

我该怎么做才能确保字符串被垃圾回收?

谢谢你的帮助

编辑:

1- 我在使用Django的ORM

2- 我从两个来源获取这些字符串:

2.1- 直接从socket获取(urllib2.urlopen(url).read())

2.2- 解析这些响应,从每个HTML中提取新的URI,并将其提供给系统

解决了

最后,我找到了关键。这个脚本是Django环境的一部分,似乎Django的底层在做一些缓存或类似的事情。我关闭了调试模式,一切开始按预期工作(重用标识符似乎删除了对旧对象的引用,这些对象就被垃圾回收了)。

对于使用某种框架层的Python用户,要注意配置:一些调试配置在进行大量处理时可能会导致内存泄漏。

2 个回答

0

你需要找出是谁在“内部”保存了你的字符串引用。可能是你用来写入数据库的库(你没有说明你是怎么写入数据库的)。我发现 objgraph 在处理这种任务时非常有用:https://pypi.python.org/pypi/objgraph

例如:

import objgraph
objgraph.show_backrefs([mystring], filename='a.png')
2

你说:
我发现每个新字符串(用sys.getrefcount)至少有两个引用

但是你有没有仔细看过getrefcount()的说明呢?:

sys.getrefcount()

这个函数会返回对象的引用计数。返回的计数通常比你预期的要多1,因为它还包括了作为参数传给getrefcount()的(临时)引用。

你应该多解释一下你的程序。

它所持有的HTML字符串大小是多少?
这些字符串是怎么获得的?你确定关闭了所有文件的句柄、所有的套接字连接吗……?

撰写回答