0

我想在 OS X (10.8.2) 上使用 lxml (3.2.0) 用 Python (2.7.2) 解析一个 1.6 GB XML 文件。因为我已经阅读了有关内存消耗的潜在问题,所以我已经在其中使用了 fast_iter,但是在主循环之后,它会占用大约 8 GB 的 RAM,即使它没有保留来自实际 XML 文件的任何数据。

from lxml import etree

def fast_iter(context, func, *args, **kwargs):
    # http://www.ibm.com/developerworks/xml/library/x-hiperfparse/
    # Author: Liza Daly
    for event, elem in context:
        func(elem, *args, **kwargs)
        elem.clear()
        while elem.getprevious() is not None:
            del elem.getparent()[0]
    del context

def process_element(elem):
    pass

context = etree.iterparse("sachsen-latest.osm", tag="node", events=("end", ))
fast_iter(context, process_element)

我不明白,为什么会有如此大规模的泄漏,因为元素和整个上下文正在被删除,fast_iter()而目前我什至不处理 XML 数据。

有任何想法吗?

4

1 回答 1

3

问题在于 的行为etree.iterparse()。你会认为它只为每个node元素使用内存,但事实证明它仍然将所有其他元素保留在内存中。由于您不清除它们,内存最终会爆炸,特别是在解析 .osm (OpenStreetMaps) 文件和查找节点时,但稍后会更多。

我找到的解决方案不是捕获node标签而是捕获所有标签:

context = etree.iterparse(open(filename,'r'),events=('end',))

然后清除所有标签,但只解析您感兴趣的标签:

for (event,elem) in progress.bar(context):
    if elem.tag == 'node':
        # do things here

    elem.clear()
    while elem.getprevious() is not None:
        del elem.getparent()[0]
del context

请记住,它可能会删除您感兴趣的其他元素,因此请确保在需要时添加更多 ifs。例如(这是 .osm 特定的)tags嵌套从nodes

if elem.tag == 'tag':
    continue
if elem.tag == 'node':
    for tag in elem.iterchildren():
        # do stuff

内存后来爆炸的原因非常有趣,.osm 文件的组织方式nodes先到后继。因此,您的代码在一开始就可以很好地处理节点,然后随着其余元素的运行,内存会被填满。waysrelationsetree

于 2014-08-05T09:23:56.240 回答