Недостаточно памяти с помощью простого цикла чтения Win32::Unicode::File и Strawberry Perl

Проблема, с которой я столкнулся, можно найти, запустив следующий код в Strawberry perl 5.12.3.0 в Windows XP.

    #!/usr/bin/perl -w

    use strict;
    use warnings;
    use Win32::Unicode::File;
    use Encode;

    my $fname = shift @ARGV;

    my $fh = Win32::Unicode::File->new;
    if ($fh->open('<', $fname)){
      while (my $line = $fh->readline()){}
      close $fh;
    }else{
      print "Couldn't open file: $!\n";
    }

Единственное, что здесь происходит, это то, что я выполняю readline, и это продолжает потреблять память, пока я не получаю ошибку «Недостаточно памяти» от Strawberry perl. Я использую очень большой файл, но, поскольку этот код основан на потоке, это не имеет значения. Я что-то упустил или где-то в Strawberry perl есть утечка? Я протестировал точно такой же код в ActivePerl и там он работает нормально, т.е. не ест память.

Обновление: замена Win32::Unicode::File обычным алмазным оператором работает, по крайней мере, в моем дистрибутиве. См. следующий код.

    use strict;
    use warnings;

    my $fname = shift @ARGV;

    if (open(my $fh, '<', $fname)){
      while (my $line = <$fh>){}
      close $fh;
    }else{ print "Couldn't open file: $!\n";}

Таким образом, можно предположить, что проблема связана с модулем Win32::Unicode, верно?


person Dr. Mike    schedule 03.01.2012    source источник
comment
Есть ли в файле разрывы строк? Попытка прочитать строку может закончиться чтением всего файла.   -  person ikegami    schedule 03.01.2012
comment
@ikegami да, в файле есть разрывы строк, и длина каждой строки не превышает 255 символов.   -  person Dr. Mike    schedule 03.01.2012
comment
Я бы предложил поставить оператор печати для каждой прочитанной строки вместо пустого блока, чтобы вы могли видеть, что строки действительно читаются. Просто распечатайте. сделал бы. Кроме того, убедитесь, что у вас действительно есть $line, а не @line, которая будет читать весь файл.   -  person Bill Ruppert    schedule 03.01.2012
comment
@BillRuppert Я сделал это, и файл читается и анализируется правильно. Приведенный выше код просто показывает вам основную проблему.   -  person Dr. Mike    schedule 03.01.2012
comment
Я могу воспроизвести проблему на Citrus Perl 5.12.3 с файлом размером более 600 МБ. Он даже дает сбой при использовании обычного алмазного оператора вместо Win32::Unicode::File.   -  person Stamm    schedule 04.01.2012
comment
@Stamm Я не пробовал, но тогда, по крайней мере, это очистит модуль Win32::Unicode::File от утечки памяти. Любые идеи относительно того, почему эта утечка происходит? Я в своем уме.   -  person Dr. Mike    schedule 04.01.2012
comment
@Stamm Я только что попробовал следующий код: use strict; использовать предупреждения; мое $fname = сдвиг @ARGV; if (open(my $fh, '‹', $fname)){ while (my $line = ‹$fh›){} close $fh; }else{ print Не удалось открыть файл: $!\n;} и это не доставило мне никаких проблем.   -  person Dr. Mike    schedule 04.01.2012
comment
Извините, я испортил свои предыдущие тесты. Действительно, с алмазным оператором он работает, как и ожидалось. И это в 50 раз быстрее. Итак, Win32::Unicode::File является виновником.   -  person Stamm    schedule 04.01.2012


Ответы (2)


Может быть, $/ (или $INPUT_RECORD_SEPARATOR) — это не новая строка? Или $[ (индекс первого элемента массива и первого символа в (под)строке) не равен 0.

Эти две переменные используются модулем во время чтения или строки чтения.

Кстати: это так чертовски медленно, потому что он использует 3 вызова функций для чтения каждой строки по одному символу за раз, а затем вызывает Encode::decode для каждого прочитанного символа, а затем добавляет его в буфер строки, который readline возвращает вашему коду. Фу!

person Chris H    schedule 27.01.2012

Думаю, немного неортодоксально, но я отвечу на свой вопрос. Я заменил пакет Win32::Unicode::File пакетом Path::Class::Unicode вместо чтения файла unicode. Это работает нормально (т. е. не потребляет памяти), поэтому похоже, что проблема в пакете Win32::Unicode::File и, скорее всего, является ошибкой. Я связался с автором пакета, и он изучает его. Пожалуйста, дайте мне знать, если вы хотите, чтобы я предоставил код. Это довольно просто.

person Dr. Mike    schedule 30.01.2012