当我在Perl中将文件读入内存时,为什么要耗尽这么多内存?

时间:2010-10-05 01:03:38

标签: perl gzip

我有一个310MB大小的文本文件(未压缩)。当使用PerlIO::gzip打开文件并将其解压缩到内存中时,在perl耗尽内存之前,此文件很容易填充2GB的RAM。

文件打开如下:

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

显然,这是一种在perl中轻松打开gzip文件的超级便捷方式,但它占用了大量的空间!我的下一步是将文件解压缩到HD,将文件行读取到@lines,在@lines上操作,然后将其压缩。有没有人知道为什么打开压缩文件时消耗的内存超过7倍?有没有人对如何将这个gzip压缩文件解压缩到内存中而不采用可笑的内存量有另一种想法?

3 个答案:

答案 0 :(得分:22)

您正在将该文件的所有内容读入@lines数组。当然,这会将所有未压缩的内容拉入内存。您可能想要的是逐行读取句柄,一次只在内存中保留一行:

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

答案 1 :(得分:17)

当你这样做时:

my @lines = <FOO>;

您正在创建一个数组,其元素与file中的行数一样多。每行100个字符,大约有340万个数组条目。每个数组条目都会产生开销,这意味着内存占用量将远远大于文件的未压缩大小。

您可以逐行避免诽谤和处理文件。这是一个例子:

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

答案 2 :(得分:-5)

有了这么大的文件,我只看到一个解决方案:你可以使用命令行来解压缩/压缩文件。在Perl中进行操作,然后再使用外部工具压缩/解压缩文件:)