2010-10-05 19 views
5

Tengo un archivo de texto de 310 MB de tamaño (sin comprimir). Cuando usa PerlIO::gzip para abrir el archivo y descomprimirlo en la memoria, este archivo llena fácilmente 2GB de RAM antes de que perl se quede sin memoria.¿Por qué agoto tanta memoria cuando leo un archivo en la memoria en Perl?

se abre el archivo de la siguiente manera:

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

Obviamente, esta es una manera muy práctico para abrir ficheros comprimidos con facilidad en Perl, pero ocupa una ridícula cantidad de espacio! Mi siguiente paso es descomprimir el archivo en HD, leer las líneas del archivo en @lines, operar en @lines y comprimirlo nuevamente. ¿Alguien tiene alguna idea de por qué se consume más de 7 veces la cantidad de memoria al abrir un archivo comprimido? ¿Alguien tiene una idea alternativa sobre cómo puedo descomprimir este archivo comprimido en la memoria sin que se tome una cantidad ridícula de memoria?

+0

también, Perl 5.12.1 x64 en Mac OS X 10.6 –

+8

Sólo hizo la pregunta 7000a etiquetados 'perl' en stackoverflow. ¡Felicitaciones! :-) – rafl

Respuesta

17

Al hacer:

my @lines = <FOO>; 

que está creando una matriz con tantos elementos como hay líneas en file. Con 100 caracteres por línea, eso es alrededor de 3.4 millones de entradas de matriz. Hay una sobrecarga asociada con cada entrada de matriz, lo que significa que la huella de memoria será mucho mayor que el tamaño sin comprimir del archivo.

Puede evitar sorber y procesar el archivo línea por línea. Aquí está un ejemplo:

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

Y, de hecho,

#!/usr/bin/perl 

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

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

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

no tiene problemas.

para tener una idea de la sobrecarga de la memoria, nota:

#!/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); 

Salida:

Scalar: 136 
Array: 256
22

Está leyendo todo el contenido del archivo en una matriz de @lines. Por supuesto, eso atraerá todo el contenido sin comprimir a la memoria. Lo que podría haber querido lugar es la lectura de su mango línea por línea, sólo el mantenimiento de una línea a la vez en la memoria:

open my $foo, '<:gzip', 'file.gz' or die $!; 
while (my $line = <$fh>) { 
    # process $line here 
} 
+0

Esto no mantendrá solo una línea en la memoria ya que la compresión requerirá un poco de espacio para trabajar. –

-6

Con este tipo de archivos de gran tamaño sólo veo una solución: se puede usar la línea de comandos para descomprimir/comprimir archivo. Haga su manipulación en Perl, a continuación, utilizar herramientas externas de nuevo para comprimir/descomprimir el archivo :)

+1

Es posible hacer todo eso dentro de Perl 5 sin recurrir a herramientas externas. El problema es la lectura de todos los datos en la memoria a la vez, en lugar de procesarlos línea por línea. –

Cuestiones relacionadas