为什么 lxml.etree.HTMLPullParser 内存泄漏?

Why is this lxml.etree.HTMLPullParser leaking memory?

我正在尝试在 Linux Mint 上使用 lxml 的 HTMLPullParser,但我发现内存使用量不断增加,我不确定为什么。这是我的测试代码:

# -*- coding: utf-8 -*-
from __future__ import division, absolute_import, print_function, unicode_literals
import lxml.etree
import resource
from io import DEFAULT_BUFFER_SIZE

for _ in xrange(1000):
with open('Whosebug.html', 'r') as f:
    parser = lxml.etree.HTMLPullParser()
    while True:
        buf = f.read(DEFAULT_BUFFER_SIZE)
        if not buf: break
        parser.feed(buf)
    parser.close()

    # Print memory usage
    print((resource.getrusage(resource.RUSAGE_SELF)[2] * resource.getpagesize())/1000000.0)

Whosebug.html 是我保存在与 python 脚本相同的文件夹中的 Whosebug 主页。我试过添加显式删除和清除,但到目前为止没有任何效果。我做错了什么?

解析器构造的元素正在泄漏,我在您的代码中看不到 API 合同违规导致它。由于对象在使用 gc.collect() 的手动垃圾收集 运行 中幸存下来,您最好的选择可能是尝试不同的解析策略作为解决方法。

为了查看根本原因,我使用内存探索模块 objgraph and installed xdot 查看它创建的图表。

在 运行 代码之前,我 运行:

In [3]: import objgraph

In [4]: objgraph.show_growth()

在 运行 代码之后,我 运行:

In [6]: objgraph.show_growth()
tuple                  1616      +147
_Element                146      +146
list                   1100       +24
wrapper_descriptor     1423       +15
weakref                1155        +6
getset_descriptor       677        +4
dict                   2777        +4
member_descriptor       315        +3
method_descriptor       891        +2
_TempStore                2        +1

In [7]: import random

In [8]: objgraph.show_chain(
   ...: objgraph.find_backref_chain(
   ...: random.choice(objgraph.by_type('_Element')), objgraph.is_proper_module))
Graph written to /tmp/objgraph-bfuwa9.dot (8 nodes)
Spawning graph viewer (xdot)

注意:根据浏览的网页,数字可能与您看到的不同。