2

Я начинаю начинать. Я пытаюсь построить 2d-массив во время выполнения из двоичного файла. Я получаю ошибку «из памяти». Я использую Perl 5.16.3 в Windows 7. Размер моего входного файла составляет ~ 4.2MB. Моя система имеет физическую память 4 ГБ, и я использую 90% использования, а затем обнаруживаю ошибку из памяти при запуске этого кода.Perl: Ошибка памяти при построении массива 2d во время выполнения

Я пробовал много способов отладить это. Только если я уменьшу b32 до b16 или меньше, я могу успешно работать. Даже при этом, если размер файла превышает 4 МБ, ошибка появляется снова. Я пытался смотреть на использование физической памяти в диспетчере задач, выполняя код, он продолжает расти.

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

#!/usr/bin/perl 
use strict; 
use warnings; 

open(DATA, 'debug.bin') or die "Unable to open:$!"; 
binmode DATA; 
my ($data, $n, $i); 
my @2dmatrix; 
while ($n = read DATA, $data, 4) { 
    push @2dmatrix, [ split('', unpack('b32', $data)) ]; 
} 
print scalar(@2dmatrix); 
print "completed reading"; 
close(DATA); 

Просто, чтобы убрать требование. Из сборки массива 2d мне нужно извлечь содержимое из столбца A, соответствующего определенному шаблону (11111111000000001111111100000000) в столбце B. Это необходимо сделать для 4-х колонок с размером файла 500 Мб.

+0

Попробуйте обрезать данные на меньший размер блоков, которые могут помочь вам в устранении ошибки в памяти. – Praveen

+0

требования к английскому языку гораздо более двусмысленны, чем код; вам нужно всего 40 строк за раз? – ysth

+0

@ysth Да. но 40 строк не могут быть решены напрямую. Я должен игнорировать множество строк между ними, в зависимости от варианта использования. Итак, я выбрал сборку всего массива и процесс. – tirumalesh

ответ

6

Это не утечка памяти, ваша программа просто неэффективна при использовании памяти.

На каждые 4 байта, которые вы читаете, вы делаете unpack 'b32', который создает 32-символьную строку; split //, который превращает его в 32 строки с 1 символом, создайте arrayref из результирующего списка и нажмите arrayref на @2dmatrix. Это приводит к:

  • 32 струнных органов, каждый из которых по меньшей мере, 2 байта (для "0\0" или "1\0"), хотя Perl может решить использовать больше, чтобы избежать перераспределений, если строки расти: 64 байта.
  • 32 SVPVs (скалярные переменные, содержащие строки, по 28 байт по 32 бит, по 40 байт на 64-разрядных): 896 или 1280 байт.
  • 1 массив массивов с 32 элементами: 128 байт на 32-битный, 256 байтов на 64-разрядный.
  • 1 AV (переменная массива): 28 байт по 32-битной, 40 байт на 64-разрядной.
  • 1 SVRV (скаляр, содержащий ссылку): 16 байт по 32-битным, 24 байтам на 64-битных.
  • 1 запись в массиве @2dmatrix: 4 байта по 32-битным, 8 байтам на 64-разрядных.

с результатом 1136 байт на 4 байта (284x умножения) на 32-битной и 1672 байт на 4 байта (418x умножение) на 64-бит, без учета постоянных факторов, и тот факт, что Perl может выбрать для использования больших строковых тел (в двух версиях perl, которые я тестировал здесь, я получил либо 10, либо 16 байт, а не 2.) Таким образом, ваша программа будет использовать более 1,1 ГБ памяти для входа 4,2 МБ на 32-битной системе , и более 1,7 ГБ памяти для входа 4,2 МБ в 64-битной системе.

Решения здесь для хранения и доступа к данным в более эффективном способе, но я не могу давать какие-либо конкретные рекомендации, потому что вы не сказали, что вы на самом деле пытаетесь сделать с @2dmatrix как только вы Это.

+0

Сохранение чисел вместо строк является легко полученной эффективностью ('[map $ _? 1: 0, split ...]' вместо '[split ...]'), сохраняя 576 байт в 64-битном perl. – ysth

+1

@ysth да, я бы предположил хранить 32-битные числа и использовать комбинацию индексирования массива и битрейта для доступа к членам как к достойному компромиссу между пространством и удобством (доводит вас до ~ 1 миллиона массивов записей без косвенности) но что-нибудь от 'vec' до фактического чтения файла вообще не могло работать, поэтому я хотел бы услышать больше требований :) – hobbs

+0

, если они собираются внести изменения в код в том, что на самом деле использует массив массивов, просто чтение всего файла в строку и использование vec, вероятно, проще всего – ysth

1

Забудьте прочесть в памяти содержимое всего файла.Сделать функцию для доступа к данным (х, у), которая в дальнейшем будет иметь доступ значение в файле также рассмотреть глядя на http://search.cpan.org/~leont/File-Map-0.63/lib/File/Map.pm#Advantages_of_memory_mapping

+0

4MB данных может поместиться в памяти просто отлично, без отображения памяти. Проблема в том, что нынешний подход OP крайне неэффективен. –

+0

Извините Недоразумение. Я думал о файле 4Gb. –

0

Чтение всего файла в строку и с помощью VEC выглядит так:

my $data = do { local $/; <DATA> }; 

Тогда получить конкретный ряд/столбец, используйте:

$value = vec($data, $row*32+$col, 1); 
+0

Я пытаюсь понять ваш пример, $ value выше читает элемент [$ row, $ col] в массиве 2d. Могу ли я читать массив строк/столбцов из vec? – tirumalesh

+0

использовать 'vec ($ data, $ row * 32 + $ col, 1)' вместо '$ twodarray [$ row] [$ col]'; это яснее? – ysth