Почему я использую столько памяти при чтении файла в память на Perl? - PullRequest
5 голосов
/ 05 октября 2010

У меня есть текстовый файл размером 310 МБ (без сжатия). При использовании PerlIO :: gzip для открытия файла и его распаковки в память этот файл легко заполняет 2 ГБ ОЗУ, прежде чем Perl исчерпает память.

Файл открывается, как показано ниже:

open FOO, "<:gzip", "file.gz" or die $!;
my @lines = <FOO>;

Очевидно, что это супер удобный способ легко открывать сжатые файлы в Perl, но он занимает невероятное количество места! Мой следующий шаг - распаковать файл на HD, прочитать строки файла в @lines, работать с @lines и снова сжать его. У кого-нибудь есть идеи, почему при открытии zip-файла используется в 7 раз больше памяти? У кого-нибудь есть альтернативная идея относительно того, как я могу распаковать этот сжатый файл в память, не занимая при этом смешного количества памяти?

Ответы [ 3 ]

22 голосов
/ 05 октября 2010

Вы читаете все содержимое файла в массив @lines. Конечно, это вытянет весь несжатый контент в память. Вместо этого вы, возможно, захотели бы построчно читать из вашего дескриптора, сохраняя в памяти только одну строку:

open my $foo, '<:gzip', 'file.gz' or die $!;
while (my $line = <$fh>) {
    # process $line here
}
17 голосов
/ 05 октября 2010

Когда вы делаете:

my @lines = <FOO>;

, вы создаете массив с таким количеством элементов, сколько строк в file.При 100 символах в строке это около 3,4 миллиона записей массива.С каждой записью массива связаны накладные расходы, что означает, что объем занимаемой памяти будет намного больше, чем просто размер несжатого файла.

Вы можете избежать расплывчатости и обрабатывать файл построчно.Вот пример:

C:\Temp> dir file
2010/10/04  09:18 PM       328,000,000 file
C:\Temp> dir file.gz
2010/10/04  09:19 PM         1,112,975 file.gz

И, действительно,

#!/usr/bin/perl

use strict; use warnings;
use autodie;
use PerlIO::gzip;

open my $foo, '<:gzip', 'file.gz';

while ( my $line = <$foo> ) {
    print ".";
}

не имеет проблем.

Чтобы получить представление об объеме памяти, обратите внимание:

#!/usr/bin/perl

use strict; use warnings;
use Devel::Size qw( total_size );

my $x = 'x' x 100;
my @x = ('x' x 100);

printf "Scalar: %d\n", total_size( \$x );
printf "Array:  %d\n", total_size( \@x );

Вывод:

Scalar: 136
Array:  256
0 голосов
/ 05 октября 2010

С такими большими файлами я вижу только одно решение: вы можете использовать командную строку для распаковки / сжатия файла. Сделайте ваши манипуляции в Perl, затем снова используйте внешние инструменты для сжатия / распаковки файла:)

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