【问题标题】:Apparent memory leak in Python script using Django使用 Django 的 Python 脚本中的明显内存泄漏
【发布时间】: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_date url 函数使用来自外键字段的值,所以我仍然会必须获取对象本身。或者是否有类似的函数来获取某个特定成员函数的结果?
  • docs.djangoproject.com/en/dev/ref/models/querysets/#values-list 似乎可以使用object.values_list('foreignobject__url')
  • 我没有意识到这是可能的!感谢您的建议,在对我们的 url() 函数进行大量繁琐的复制以在 dicts 上使用之后,脚本运行速度更快、更轻了几个数量级!如果你把它作为答案,我很乐意接受它

标签: python django memory-leaks out-of-memory


【解决方案1】:

The docs 似乎建议使用object.values_list('foreignobject__url'),它允许相关字段。因此,如果 foreignobject 是模型上的外键,它本身包含字段 url,则可以安全地使用 values_list 以减少数据库调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-05
    • 2013-07-09
    • 2022-12-17
    • 1970-01-01
    • 1970-01-01
    • 2012-06-23
    相关资源
    最近更新 更多