【发布时间】:2014-01-17 15:52:06
【问题描述】:
我有一个用于构建站点地图的脚本 - 对于每个相关模型,我都会生成许多分页站点地图,每个对象都有一个 URL,并且我打算每周再次运行该脚本使用新数据重新生成站点地图。
但是,当我在我的 Ubuntu 服务器上运行此脚本时,内存使用量不断攀升,直到该进程最终被操作系统杀死。这是我目前无法通过的功能:
def xml_for_page(object):
sOutText = "\t<url>\n"
sURL = object.url()
sOutText += "\t\t<loc>http://www.mysite.com%s</loc>\n" % sURL
sLastModified = object.last_status_change.isoformat()
sOutText += "\t\t<lastmod>%s</lastmod>\n" % sLastModified
sChangeFreq = "monthly"
sOutText += "\t\t<changefreq>%s</changefreq>\n" % sChangeFreq
sOutText += "\t</url>\n"
return sOutText
def generate_object_map():
# Do this in chunks of ITEMS_PER_FILE
bFinished = False
iOffset = 0
iCurrentPage = 0
while not bFinished:
objResults = PageObject.objects.filter(submission_status=SUBMISSION_STATUS_ACCEPTED).order_by('-popularity')[iOffset:iOffset+ITEMS_PER_FILE]
if objResults.count() < 1:
break
sFilename = "%s/sitemap-objects-%i.xml" % (OUTPUT_DIR, iCurrentPage)
fObjects = open(sFilename, 'w')
fObjects.write('<?xml version="1.0" encoding="UTF-8"?>\n')
fObjects.write('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n')
for object in objResults:
fObjects.write(xml_for_page(object))
fObjects.write('</urlset>')
fObjects.close()
iOffset += ITEMS_PER_FILE
iCurrentPage += 1
所以这里发生的事情是:while not bFinished 循环的每次迭代我们都会为我们所在的页面创建一个新文件,并在数据库中查询该特定对象集。然后我们遍历这些对象并将该页面的 XML 写入站点地图文件。编写完这些文件后,我们关闭该文件并启动另一个文件。这种分页行为的原因是,当将所有条目写入一个文件时,我很快就达到了内存限制。这比当时表现得更好,但是当我使用resource 跟踪内存使用情况时,我可以看到它在每个文件写入后都在攀升。数据库中大约有 200,000 个这种类型的对象,所以理想情况下,我需要使其尽可能可扩展。但是,我看不到在主循环的每次迭代之后内存是如何被保留的:QuerySet 对象在每次迭代后被重写,文件句柄也在每次迭代后关闭并重新分配。我认为 Python 的 GC 行为将允许在重新分配变量后清理不再使用的对象。不是这样吗?
【问题讨论】:
-
object.url()可以做点什么吗?如果您仅用一组字符串替换 django 模型并将其写入文件,以查看模型或您的xml_for_page是否与它有关。继续削减示例代码,这就是我的意思 -
如果您要实现可扩展性,为什么不在您的模型上使用
.defer或.only甚至.values_list?数据库调用的数量越少越好。 -
url()函数在这里限制了我 - 虽然我可以通过values_list获取 ID 和last_modified_dateurl函数使用来自外键字段的值,所以我仍然会必须获取对象本身。或者是否有类似的函数来获取某个特定成员函数的结果? -
docs.djangoproject.com/en/dev/ref/models/querysets/#values-list 似乎可以使用
object.values_list('foreignobject__url') -
我没有意识到这是可能的!感谢您的建议,在对我们的
url()函数进行大量繁琐的复制以在 dicts 上使用之后,脚本运行速度更快、更轻了几个数量级!如果你把它作为答案,我很乐意接受它
标签: python django memory-leaks out-of-memory