Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > XML::Libxml минимизация расхода памяти


Автор: shamber 19.8.2009, 11:13
Здравствуйте всем!!!


есть файлик Excel xml размером ~ 6мб.
я его парсю
Код

$doc = $parser->parse_fh($fh);

получается что памяти выделилось допустим 30 мб.
Дальше мне нужно пройтись по всем строкам в файлике за это отвечает тег Row
если сделать так
Код

my @list = $doc->getElementsByTagName("Row");

то выделиться еще около 25 мб. Итого 55 метров.
А хочется не выделять дополнительные 25 метров
А можно ли как-то обойти их по одному, что то типа :
findnode("Row")
nextnode()
?
Точнее мне кажется что можно, но я никак не могу понять как smile

Автор: ginnie 19.8.2009, 12:07
shamber, может использовать SAX-парсер (например, XML::Twig)?

Автор: shamber 19.8.2009, 14:13
спасибо, буду пробовать

Автор: KSURi 19.8.2009, 14:20
Код

for my $node ($xml->findnodes('//Row')) {
  # ...
}

?

Добавлено @ 14:22
Хотя нет, не то. Наверное все-таки надо SAX-парсер использовать.
Но на всякий случай померяйте вариант с использованием XML::LibXML::NodeList.

Автор: shamber 19.8.2009, 14:52
Вообщем глянул внимательно, понял что приврал smile
6 мб в Dom занимает 70 мб smile
Код

my @list = $doc->getElementsByTagName("Row");

прибавляет 1,5 мб.

А в SAX(XML::Twig) как перейти к следующему элементу?
т.е.
first_child нашел,  а следующий?

Автор: ginnie 19.8.2009, 15:00
Цитата(shamber @  19.8.2009,  14:52 Найти цитируемый пост)
А в SAX(XML::Twig) как перейти к следующему элементу?

Предположу, что next_sibling. Либо можно children использовать, чтобы получить список.

Автор: shamber 20.8.2009, 09:30
Эх, Twig тормозит smile

Автор: shamber 20.8.2009, 09:58
Чего-то не понимаю, подскажите где ошибка.
делаю так

Код

my @twig_options = (keep_encoding => 1, TwigRoots=> {Row=>\&row},TwigPrintOutsideRoots => 0);
my $twig = XML::Twig->new(@twig_options);
$twig->parsefile($file);

sub row{
    # let's use the attribute nb as a prefix to the title
    my @title= $_[1]->children( 'Cell'); # find the title
    $str = $title[0]->text;
    undef (@title);
    
    $_[0]->purge;            # outputs the section and frees memory
 }

А расход памяти увеличивается.

Автор: ginnie 20.8.2009, 10:51
shamber, вроде все правильно делаешь. Насколько сильный расход памяти?

Автор: shamber 20.8.2009, 10:55
ginnie, он конечно же меньше чем XML::LibXML.
Но для файла 6 мб, в начале старта скрипта памяти выделяется 9 мб. под конец работы уже 25 мб.
Но не понятно мне почему она во время работы все время увеличивается.

Добавлено через 44 секунды
мне казалось что после purge память должна освобождаться

Автор: ginnie 20.8.2009, 11:08
shamber, памяти должно использоваться сильно меньше чем в XML::LibXML, т.к. файл читается фрагментами. Надо несколько вызовов row() посмотреть и определить, когда память расходуется.
P.S. Я использовал XML::Twig для обработки xml-файла более 60 Мб, только особого внимания на расход памяти не обращал, т.к. для меня оно значения особого не имело.

Автор: shamber 20.8.2009, 11:22
Код

#!/usr/bin/perl -w
use XML::Twig;
use Win32::API;
use IO::File;


my $start_usage = win32_size_check();

my $file = 'рц.xls';
my $LOG;
$LOG = IO::File->new();
$LOG->open("> "."memory.log");
my @twig_options = (keep_encoding => 1, TwigRoots=> {Row=>\&row},TwigPrintOutsideRoots => 0);
my $twig = XML::Twig->new(@twig_options);
$LOG->print('start ' , $start_usage,"\n");
$twig->parsefile($file);
exit;


sub row{
    $LOG->print('################# ', "\n");
    $LOG->print('in row: ', win32_size_check() - $start_usage, "\t");
    # let's use the attribute nb as a prefix to the title
    my @title= $_[1]->children( 'Cell'); # find the title
    $LOG->print('after children: ', win32_size_check() - $start_usage, "\t");
    my $str = $title[0]->text;
    undef (@title);
    $LOG->print('after undef: ', win32_size_check() - $start_usage, "\t");
    
    $_[0]->purge;            # outputs the section and frees memory
    $LOG->print('after purge: ', win32_size_check() - $start_usage, "\n");
 }

sub win32_size_check {
    # get handle on current process
    my $GetCurrentProcess = new Win32::API('kernel32', 
                                           'GetCurrentProcess', 
                                           [], 
                                           'I');
    my $hProcess = $GetCurrentProcess->Call();

    
    # memory usage is bundled up in ProcessMemoryCounters structure
    # populated by GetProcessMemoryInfo() win32 call
    my $DWORD = 'B32';  # 32 bits
    my $SIZE_T = 'I';   # unsigned integer

    # build a buffer structure to populate
    my $pmem_struct = "$DWORD" x 2 . "$SIZE_T" x 8;
    my $pProcessMemoryCounters = pack($pmem_struct, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    
    # GetProcessMemoryInfo is in "psapi.dll"
    my $GetProcessMemoryInfo = new Win32::API('psapi', 
                                              'GetProcessMemoryInfo', 
                                              ['I', 'P', 'I'], 
                                              'I');

    my $bool = $GetProcessMemoryInfo->Call($hProcess, 
                                           $pProcessMemoryCounters, 
                                           length($pProcessMemoryCounters));

    # unpack ProcessMemoryCounters structure
    my ($cb, 
        $PageFaultCount, 
        $PeakWorkingSetSize,
        $WorkingSetSize,
        $QuotaPeakPagedPoolUsage,
        $QuotaPagedPoolUsage,
        $QuotaPeakNonPagedPoolUsage,
        $QuotaNonPagedPoolUsage,
        $PagefileUsage,
        $PeakPagefileUsage) = unpack($pmem_struct, $pProcessMemoryCounters);


    my $size = int($WorkingSetSize/1024);
    return ($size);
}

memori.log
Код

start 9144
############
in row: 364    after children: 376    after undef: 376    after purge: 376
############
in row: 384    after children: 384    after undef: 384    after purge: 384
############
in row: 384    after children: 384    after undef: 384    after purge: 384
############
in row: 388    after children: 388    after undef: 388    after purge: 388
############
in row: 388    after children: 388    after undef: 388    after purge: 388
############
in row: 396    after children: 400    after undef: 400    after purge: 400
............
in row: 18208    after children: 18208    after undef: 18208    after purge: 18208
############
in row: 18216    after children: 18216    after undef: 18216    after purge: 18216
############
in row: 18220    after children: 18220    after undef: 18220    after purge: 18220


Добавлено через 1 минуту и 13 секунд
Я так понимаю не освобождается память после  undef (@title);

Добавлено через 2 минуты и 12 секунд
хотя и после purge растет :(
каждый Row приблизительно одного содержания.

Автор: ginnie 20.8.2009, 11:33
shamber, уменьшения используемой памяти, вроде, быть не должно, т.к. интерпретатор ее системе не отдает. Не должно быть большого роста.

undef (@title); можно убрать, оно только замедляет работу, т.к. каждый вызов будет память заново выделяться.

Автор: shamber 20.8.2009, 11:45
Цитата(ginnie @  20.8.2009,  11:33 Найти цитируемый пост)
undef (@title)

а вот здесь в http://forum.vingrad.ru/index.php?showtopic=205460&view=findpost&p=1474100
выделение памяти увеличивается.

Автор: ginnie 20.8.2009, 11:55
shamber, без undef (@title) память остается зарезервирована для функции, а так как эта функция в нашем случае вызывается много раз, то это хорошо.

Автор: shamber 20.8.2009, 12:18
понятно. получается, что в xml::twig после каждого вызова row забирает себе еще памяти.

Автор: ginnie 20.8.2009, 12:26
shamber, если есть возможность, проверьте на другой операционной системе, если там память будет расходоваться аналогично, значит что-то в XML::Twig (по мотивам http://aspn.activestate.com/ASPN/Mail/Message/perl-xml/3688134).

Автор: shamber 20.8.2009, 13:06
К сожалению сейчас проверить не могу, но если кто может потестить прикладываю тестовый файлик. Это Excel файл сохраненный как xml 2003.


Автор: ginnie 20.8.2009, 14:08
Мои результаты:

WinXP

start 9436
################# 
in row: 348    after children: 352    after undef: 352    after purge: 352
################# 
in row: 356    after children: 356    after undef: 356    after purge: 356

...

################# 
in row: 404    after children: 404    after undef: 404    after purge: 404
################# 
in row: 404    after children: 404    after undef: 404    after purge: 404


FreeBSD

start 25260
#################
in row: 404     after children: 428     after undef: 428        after purge: 428
#################
in row: 428     after children: 428     after undef: 428        after purge: 428

...

#################
in row: 476     after children: 476     after undef: 476        after purge: 476
#################
in row: 476     after children: 476     after undef: 476        after purge: 476

Автор: shamber 20.8.2009, 14:12
все-таки увеличивается. Значит проблема в коде XML::Twig. :(

Автор: ginnie 20.8.2009, 14:19
shamber, а какое у тебя максимальное приращение по памяти между вызовами функции, не посмотришь? Просто память всего несколько раз увеличивается за все строчки.

Автор: shamber 20.8.2009, 14:21
Код

start size: 9136
############
in row: 332    after children: 336    after purge: 340
.......................
############
in row: 1036    after children: 1036    after purge: 1036

странно, что у меня ситуация хуже.
704 кб. А у тебя 56 кб. 

а версия XML::Twig?
у меня  WinXP 
 XML::Twig 3.32

Автор: ginnie 20.8.2009, 14:25
Версия такая-же, XML::Twig 3.32.

Автор: shamber 20.8.2009, 14:35
Просто так, для точности, вы с моим файликом работали?
Если да, то мне совсем непонятно, что с памятью происходит. В особенности с моей.

Автор: ginnie 20.8.2009, 14:38
Цитата(shamber @  20.8.2009,  14:35 Найти цитируемый пост)
Просто так, для точности, вы с моим файликом работали?

Да, работал с файлом __.7z 2,62 Kb, который был выше.

Автор: shamber 20.8.2009, 21:46
http://xmltwig.com/xmltwig/XML-Twig-FAQ.html#Q12
у меня модуль WeakRef не стоял, но после установки к сожалению ничего не изменилось. :(

Автор: ginnie 20.8.2009, 21:50
shamber, WeakRef нужен только для perl 5.6.0, т.к. там не было слабых ссылок.

Автор: shamber 20.8.2009, 21:59
А с модулем Devel::Monitor работали?

Автор: ginnie 21.8.2009, 00:35
Нет, с Devel::Monitor не работал, спасибо за наводку, посмотрю. Для личных нужд использовал Devel::Leak::Object. Есть проблемы с XML::Twig, которые показывает Devel::Monitor?

Автор: shamber 21.8.2009, 08:23
Пока еще нет.

Автор: ginnie 24.9.2009, 00:06
shamber, пришлось недавно переписывать загрузчик в БД из XML. Раньше XML были поменьше и скорость работы сильно не беспокоила. Сейчас ситуация изменилась, надо грузить 8 XML-файлов от 100000 до 360000 товаров в каждом (по каждому товару некоторый набор данных). XML::Twig не очень порадовал скоростью, пришлось искать альтернативу. Пока остановился на XML::Parser. Он работает заметно быстрее, только там вся идеология работы отличается от XML::Twig.

Автор: KSURi 24.9.2009, 08:11
Если структура XML не сложная, посмотри XML::Bare

Автор: ginnie 24.9.2009, 08:25
KSURi, на таких объемных (100 - 300 Мб) файлах подходит только SAX-парсер.

Автор: shamber 25.9.2009, 11:26
ginnie, спасибо за идею. я тоже не в восторге от XML::Twig. Мне он показался всеж-таки жутко медленным.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)