в перл. как хеш хранит данные в памяти - PullRequest
4 голосов
/ 04 августа 2010

У меня большой xml-файл, и его разбор занимает много памяти.
так как я считаю, что большая часть из-за большого количества имен пользователей в файле.
Я изменил длину каждого имени пользователя с ~ 28 байт до 10 байт.
и беги снова. но он все еще занимает почти столько же памяти.
XML-файл до сих пор анализируется с помощью SAX, и во время обработки получается хранится в хэш-структуре, например:
$this->{'date'}->{'school 1'}->{$class}->{$student}...

почему после того, как я уменьшу длину имени ученика, памяти так много? Является ли это возможным когда данные хранятся в хэш-памяти. Есть много накладных расходов, независимо от того, насколько длинна строка?

Ответы [ 3 ]

5 голосов
/ 04 августа 2010

Хэши Perl используют технику, известную как цепочка ведер.Все ключи с одинаковым хешем (см. Макрос PERL_HASH_INTERNAL в hv.h) помещаются в один и тот же «сегмент», линейный список.

Согласно перданным документация

Если вы оцениваете хеш в скалярном контексте, он возвращает false, если хеш пуст.Если есть какие-либо пары ключ / значение, возвращается true;точнее, возвращаемое значение представляет собой строку, состоящую из числа используемых сегментов и количества выделенных сегментов, разделенных косой чертой.Это очень полезно только для того, чтобы выяснить, плохо ли работает алгоритм внутреннего хеширования Perl для вашего набора данных.Например, вы добавляете 10 000 вещей в хеш, но оценка %HASH в скалярном контексте показывает "1/16", что означает, что было затронуто только одно из шестнадцати сегментов, и предположительно содержит все 10000 ваших элементов.Это не должно случиться.Если связанный хеш оценивается в скалярном контексте, это приведет к фатальной ошибке, поскольку эта информация об использовании сегмента в настоящее время недоступна для связанных хешей.

Чтобы увидеть, имеет ли ваш набор данных патологическое распределение, вы можетепроверить различные уровни в скалярном контексте, например, ,

print scalar(%$this), "\n",
      scalar(%{ $this->{date} }), "\n",
      scalar(%{ $this->{date}{"school 1"} }), "\n",
      ...

. Несколько устаревший обзор см. в Как реально работают хеши на perl.com.

Скромное сокращение длин имен учеников, клавиши на четыре уровня ниже, не будет иметь существенного значения.В общем, реализация Perl имеет сильный уклон к выбрасыванию памяти при проблемах.Это не Фортран твоего отца.

0 голосов
/ 05 августа 2010

Может быть полезно использовать модуль Devel :: Size , который может сообщать о том, насколько велики различные структуры данных:

use Devel::Size qw(total_size);
print "Total Size is: ".total_size($hashref)."\n";
0 голосов
/ 04 августа 2010

Да - очень много накладных расходов.Если возможно, не храните данные в виде полного дерева, тем более что вы используете SAX-анализатор, который освобождает вас от необходимости делать это навязанным DOM.

Если вы ДОЛЖНЫ хранить вседерево, один из возможных обходных путей - хранение массивов массивов - например, вы сохраняете все имена учеников в массиве (скажем, «mary123456» хранится в $students[11], а затем сохраняете значение хеша, которое было бы ...->{"mary123456"} как * 1005).* вместо этого.

Это увеличит время обработки из-за дополнительных уровней косвенной адресации, но может уменьшиться из-за меньшего использования памяти и, следовательно, меньшего количества операций подкачки / перебора.

Другой вариант - использование хэшей, связанных с файламихотя, конечно, он будет ДЕЙСТВИТЕЛЬНО медленным из-за узкого места дискового ввода-вывода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...