Модуль python lxml: синтаксический разбор XML-файла емкостью 350 МБ использует 6 ГБ RAM, почему? [Дубликат]

Управляемая строка не совпадает с символом char *. Что происходит под прикрытием, так это то, что код маршалинга на слое interop делает копию неуправляемой строки, чтобы преобразовать ее в управляемую строку, но она не может освободить эту память, поскольку она не знает, как она была выделена.

Однако вы можете попробовать выделить и вернуть BSTR вместо char *.

Причина, по которой это имеет значение, - это то, как выделяются char * и BSTR в памяти.

Символ * буферы распределяются в куче среды выполнения C ++ с использованием частных процедур распределения / освобождения, которые CLR ничего не знает, поэтому нет возможности удалить эту память. И чтобы еще хуже, буфер, который char * указывает, может быть выделен внутренней реализацией кучи DLL-кода или даже может указывать на переменную-член в частном классе.

BSTR on другая сторона выделяется с использованием WIndows API SysAllocString и освобождается SyFreeStirng, и поскольку уровень взаимодействия CLR об этих API Windows знает, как освободить BSTR от неуправляемого кода.

12
задан mvime 25 March 2012 в 00:25
поделиться

3 ответа

for event, element in etree.iterparse(path_to_file, tag="BlogPost"):
    for child in element:
        print child.tag, child.text
    element.clear()

окончательное очищение остановит вас от использования слишком большого количества памяти.

[update:], чтобы получить «все между ... как строку», я думаю, вы хотите один из:

for event, element in etree.iterparse(path_to_file, tag="BlogPost"):
    print etree.tostring(element)
    element.close()

или

for event, element in etree.iterparse(path_to_file, tag="BlogPost"):
    print ''.join([etree.tostring(child) for child in element])
    element.close()

или, возможно, даже:

for event, element in etree.iterparse(path_to_file, tag="BlogPost"):
    print ''.join([child.text for child in element])
    element.close()
20
ответ дан andrew cooke 16 August 2018 в 10:40
поделиться
  • 1
    Это очень похоже на то, что я хотел бы немного настроить его, но это здорово. Благодаря! – mvime 25 March 2012 в 01:00
  • 2
    Есть ли способ получить все между началом и окончанием & quot; BlogPost & quot; теги как строку? – mvime 25 March 2012 в 01:58
  • 3
    @mvime, как какая строка? В формате HTML? Тогда см. Мой комментарий выше, метод lxml.etree.tostring() делает это. Вы можете вырезать ярлык открытия и закрытия с помощью нотации среза (см. в этой таблице ) – Lev Levitsky 25 March 2012 в 11:13
  • 4
    должен ли element.close() быть element.clear() в последующих фрагментах? так как я написал это, я больше не помню, но это выглядит неправильно. – andrew cooke 10 December 2012 в 14:01
  • 5
    Я также должен был разобрать XML-файл объемом 1,8 ГБ, а также использовать ту же самую функцию очистки, чтобы очистить элемент. Но clear () на самом деле не удаляет элемент из памяти, и в конце вы получаете root с пустыми элементами, который принимает память тоже. Поэтому я удалил элемент после разбора с использованием «del» заявление, которое помогло мне освободить память. Прочитайте effbot.org/zone/element-iterparse.htm#incremental-parsing , чтобы узнать, что именно происходит. – Kishor Pawar 17 March 2015 в 07:29

Для будущих поисковиков: главный ответ здесь предлагает очистить элемент на каждой итерации, но это все равно оставляет вас с постоянно увеличивающимся набором пустых элементов, которые будут медленно нарастать в памяти:

for event, element in etree.iterparse(path_to_file, tag="BlogPost"):
    for child in element:
        print child.tag, child.text
    element.clear()

^ Это не масштабируемое решение, тем более, что ваш исходный файл становится все больше и больше. Лучшее решение - получить элемент root и очистить , что каждый раз, когда вы загружаете полную запись. Это сохранит использование памяти довольно стабильно (суб-20MB, я бы сказал).

Вот решение, которое не требует поиска определенного тега. Эта функция возвращает генератор, который дает все узлы 1-го ребенка (например, <BlogPost>) под корневым узлом (например, <Database>). Это делается путем записи начала первого тега после корневого узла, затем ожидания соответствующего конечного тега, получения всего элемента, а затем очистки корневого узла.

from lxml import etree

xmlfile = '/path/to/xml/file.xml'

def iterate_xml(xmlfile):
    doc = etree.iterparse(xmlfile, events=('start', 'end'))
    _, root = next(doc)
    start_tag = None
    for event, element in doc:
        if event == 'start' and start_tag is None:
            start_tag = element.tag
        if event == 'end' and element.tag == start_tag:
            yield element
            start_tag = None
            root.clear()
9
ответ дан daveruinseverything 16 August 2018 в 10:40
поделиться
  • 1
    Ну, очень понравилась идея. Но что, если мне нужно поддерживать несколько файловых структур, как я могу это сделать, не найдя определенный тег? Например: скажем, у вас есть два типа xml-файла, в одном из которых есть source->jobs->job->..., а в другом - jobs->job. Я хочу получить только все job. Как мне это сделать с этим решением? – Ahsanul Haque 21 April 2018 в 12:02

Я предпочитаю XPath для таких вещей:

In [1]: from lxml.etree import parse

In [2]: tree = parse('/tmp/database.xml')

In [3]: for post in tree.xpath('/Database/BlogPost'):
   ...:     print 'Author:', post.xpath('Author')[0].text
   ...:     print 'Content:', post.xpath('Content')[0].text
   ...: 
Author: Last Name, Name
Content: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dictum dictum vehicula.
Author: Last Name, Name
Content: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dictum dictum vehicula.
Author: Last Name, Name
Content: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dictum dictum vehicula.

Я не уверен, что он отличается от обработки больших файлов. Замечания об этом будут оценены.

Выполняйте свой путь,

for event, element in etree.iterparse(path_to_file, tag="BlogPost"):
     for info in element.iter():
         if info.tag in ('Author', 'Content'):
             print info.tag, ':', info.text
5
ответ дан Lev Levitsky 16 August 2018 в 10:40
поделиться
  • 1
    мм. Я немного упростил дерево, и, когда я его пробую, он не работает. Например, тег BlogPost не просто '& lt; BlogPost & gt;' но '& lt; BlogPost Owner = & quot; Author & quot; Статус = & Quot; Проект & Quot; & GT;» и значения для владельца и состояния изменяются от одной записи к другой. – mvime 25 March 2012 в 00:50
  • 2
    Дополнительные атрибуты не повлияют на это; имеет значение только древовидная структура. Чтобы поймать все элементы BlogPost, вы также можете использовать for post in tree.xpath('//BlogPost'): ... – Lev Levitsky 25 March 2012 в 00:58
  • 3
    Благодаря! Я еще не могу проголосовать, но вы помогли мне понять, как это работает. Ответ, который я понимаю лучше, и я приступил к работе, правда, Андрю. – mvime 25 March 2012 в 01:00
  • 4
    иметь преимущество соотечественника; o) – andrew cooke 25 March 2012 в 01:00
  • 5
    Недавно я сделал сравнение, а iterparse с clear() потребляет много меньше памяти, чем просто XPath. – Lev Levitsky 9 April 2012 в 20:28
Другие вопросы по тегам:

Похожие вопросы: