lxml和fast_iter吃掉所有内存

时间:2013-05-10 12:34:07

标签: python xml lxml

我想在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数据。

有什么想法吗?

1 个答案:

答案 0 :(得分: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文件organized的方式是nodes先来,然后ways然后是relations。因此,您的代码在开头就可以正常使用节点,然后在etree遍历其余元素时填充内存。