如何调试Python内存故障?

11 投票
3 回答
1449 浏览
提问于 2025-04-17 18:27

编辑:非常感谢大家帮我找出bug,但由于可能很难找到或重现,任何一般的调试建议也会非常感激!帮我帮自己!=)

编辑2:正在缩小范围,注释掉一些代码。

编辑3:看起来lxml可能不是问题所在,谢谢!完整的脚本在这里。我需要仔细检查一下,找找里面的引用。它们看起来是什么样的呢?

编辑4:实际上,脚本在这个部分停止(达到100%),就是parse_og部分。所以编辑3是错误的——问题肯定出在lxml上。

编辑5 重大编辑:根据David Robinson和TankorSmash的建议,我发现了一种data内容会让lxml.etree.HTML(data)陷入疯狂循环。(我之前不小心忽略了这个,但我为自己的错误付出了代价,调试多花了两天时间! ;) 一个导致崩溃的有效脚本在这里。 (我也开了一个新问题。)

编辑6:结果发现这是lxml 2.7.8及以下版本的一个bug(至少是这样)。更新到lxml 2.9.0后,bug消失了。也感谢在这个后续问题中的朋友们。

我不知道怎么调试我遇到的这个奇怪问题。下面的代码运行大约五分钟后,内存突然被完全占满(从200MB飙升到1700MB,在达到100%期间——然后当内存满了,就进入蓝色等待状态)。

这肯定是因为下面的代码,特别是前两行。但到底发生了什么?有什么可能解释这种行为吗?

def parse_og(self, data):
    """ lxml parsing to the bone! """
    try:
        tree = etree.HTML( data ) # << break occurs on this line >>
        m = tree.xpath("//meta[@property]")

        #for i in m:
        #   y = i.attrib['property']
        #   x = i.attrib['content']
        #   # self.rj[y] = x  # commented out in this example because code fails anyway


        tree = ''
        m = ''
        x = ''
        y = ''
        i = ''

        del tree
        del m
        del x
        del y
        del i

    except Exception:
        print 'lxml error: ', sys.exc_info()[1:3]
        print len(data)
        pass

enter image description here

3 个回答

2

这可能是因为有一些引用让文档保持活跃。使用 xpath 评估得到的字符串结果时,必须小心。我看到你把 None 赋值给了 treem,但没有给 yxi 赋值。

你能把 None 也赋值给 yxi 吗?

2

在解决内存问题时,工具也会很有帮助。我发现guppy是一个非常实用的Python内存分析和探索工具。

虽然它的入门并不简单,因为缺乏好的教程和文档,但一旦你掌握了它,就会觉得它非常有用。我常用的功能有:

  • 远程内存分析(通过套接字)
  • 基本的图形界面,可以绘制使用情况图表,还可以选择显示实时数据
  • 强大且一致的接口,可以在Python命令行中探索数据使用情况
3

你可以试试使用GDB进行低级Python调试。可能是Python解释器或者lxml库里有个bug,没用额外的工具很难找到。

当你的脚本在gdb下运行时,如果CPU使用率达到100%,你可以中断脚本,然后查看堆栈跟踪。这可能会帮助你理解脚本内部发生了什么。

撰写回答