Linux Perl内存不足,但有大量可用内存
我运行的perl脚本因内存不足错误而崩溃。 该脚本在UbuntuLinux下运行,机器内存为128GB。在提交时,大部分内存都可用,但是由于脚本使用的内存超过了略高于8Gb的值,因此脚本将死亡。机器(和操作系统)是64位的 我一直在网上搜索perl中的内存分配限制,但我发现唯一的限制是机器内存,在这种情况下,即使不考虑交换分区,也有很多限制 这是我第二次遇到这个问题。我第一次使用不同的脚本时,同样的事情发生了。有人有解释吗?我看到的唯一可能性是perl对内存分配有一些限制,但我在网上搜索的所有结果似乎都与这种可能性相矛盾 提前谢谢 编辑1: 操作系统是FedoraLinux,而不是Ubuntu Linux。对不起,我弄糊涂了 编辑2: 以下是导致错误的代码部分:Linux Perl内存不足,但有大量可用内存,linux,perl,memory,Linux,Perl,Memory,我运行的perl脚本因内存不足错误而崩溃。 该脚本在UbuntuLinux下运行,机器内存为128GB。在提交时,大部分内存都可用,但是由于脚本使用的内存超过了略高于8Gb的值,因此脚本将死亡。机器(和操作系统)是64位的 我一直在网上搜索perl中的内存分配限制,但我发现唯一的限制是机器内存,在这种情况下,即使不考虑交换分区,也有很多限制 这是我第二次遇到这个问题。我第一次使用不同的脚本时,同样的事情发生了。有人有解释吗?我看到的唯一可能性是perl对内存分配有一些限制,但我在网上搜索的所有结
open( $psFullInput, "<", "fullPsIn.dat" );
$counter = <$psFullInput>; # First element is counter of spectra
while ($line = <$psFullInput>) {
@elems = split(" ",$line);
$xx = shift(@elems);
$yy = shift(@elems);
$freq = shift(@elems);
$psStored[$xx][$yy] = [];
push( @{$psStored[$xx][$yy]}, @elems );
}
close( $psFullInput );
编辑4:
下面是一个简短的代码,重现了这个问题。
正如你所看到的,我只是在填满记忆
use strict;
use warnings;
my ($xx,$yy); # Coordinate variables
my (@elems); # Array of elements to be stored on each matrix position
# Generate an array of 3000 floating point values.
# The list will be added to each array element. In the true script
# of course, each element has a list of completely different values.
# Here I use the same list of values for simplicity.
for ($xx = 1; $xx < 3000; $xx++) {
push( @elems, 1+$xx/10000 );
}
# Fill in each matrix element with the generated array
my @psStored;
for ($xx = 0; $xx < 300; $xx++) {
print "Row [$xx]\n";
for ($yy = 0; $yy < 300; $yy++) {
push( @{$psStored[$xx][$yy]}, @elems );
}
}
更新1
我进一步调查。正如建议的那样,我使用了Devel::Size并检查了$psStored的大小。输出的最后几行(以$yy为单位打印每个周期结束时的大小)为:
脚本给出错误时的进程大小为:
病毒:8943960,分辨率:8.406g
但是,我尝试了以下脚本,该脚本按照命令行上的指定分配给定大小(以GB为单位)的字符串:
use strict;
use warnings;
my $size = $ARGV[0];
print "$size GB ";
$size = int($size * 1000000000);
print "($size bytes)...\n";
my $var = "x" x $size;
print "Allocated\n";
此脚本对于大型分配没有问题。例如,我可以请求30 GB,在脚本完成之前,我从“top”获得以下输出:
病毒:56.004g,分辨率:0.054t
因此,在处理数组时,有一些东西会干扰分配,但我不明白发生了什么。我也尝试过哈希,但我得到了8-9GB左右的相同限制。我怀疑
$xx
和$yy
的值相当大且稀疏(即它们之间存在很大的差距)。这意味着Perl必须为所有中间值创建数组元素,即使其中没有数据
数据结构的设计主要取决于您在构建数据结构后想对其做什么,以及需要如何访问它。最节省空间的方法是使用散列,以便
$xx = 1024
$yy = 2048
然后将频率存储在$ps_storage[1024][2048]
中(创建$ps_storage[0]
到$ps_storage[1023]
和$ps_storage[1024][0]
到$ps_storage[1024][2047]
并将其保留为空),而不是将其存储在散列中完全不浪费空间
因为你没有说你将如何使用这些数据,所以我无法判断它是否像这样可行,但是这里有一些代码来代替你的,以这种方式构建散列
use strict;
use warnings;
use autodie;
my %ps_stored;
open my $ps_full_input, '<', 'fullPsIn.dat';
my $counter = <$ps_full_input>; # First element is counter of spectra
while (<$ps_full_input>) {
my @elems = split;
my ($xx, $yy, $freq) = @elems;
push @{ $ps_stored{"$xx,$yy"} }, \@elems;
}
close $ps_full_input;
或者,您可以在程序的顶部使用autodie,如果代码中有多个open
调用,这将非常有用
使用strict
和使用warnings
,并使用my
声明所有变量,使其尽可能接近其第一个使用点。因为您的代码是一个示例,所以不清楚您是否有strict
和warnings
,但根本没有声明,所以出现了一些问题Data::Dumper
undef
,第一次使用push
时,数组将自动激活。比如说
my $aref;
push @{ $aref }, 1, 2, 3;
具有与相同的效果
my $aref;
$aref = [];
push @{ $aref }, 1, 2, 3;
@elems
数组的引用推送到ps\u存储的列表中。我不知道$xx
和$yy
的特定值是否会出现多次,但如果它们出现了,那么您的方法只会将所有不同的@elems
集合推到一个列表中,这可能会很难再拆分为单独的集合。如果您推送一个引用,则它们保持分离
我希望这有帮助,你能用一个很短的测试脚本复制这个问题吗?也许你可以发布测试脚本,我会在我的机器上运行它。也许你没有写的一个模块是不可靠的
请使用哈希值尝试此代码
use strict;
use warnings;
my ($xx,$yy); # Coordinate variables
my (@elems); # Array of elements to be stored on each matrix position
# Generate an array of 3000 floating point values.
# The list will be added to each array element. In the true script
# of course, each element has a list of completely different values.
# Here I use the same list of values for simplicity.
for ($xx = 1; $xx < 3000; $xx++) {
push( @elems, 1+$xx/10000 );
}
# Fill in each matrix element with the generated array
my %psStored;
my $s;
$s=join('=',@elems);
for ($xx = 0; $xx < 300; $xx++) {
print "Row [$xx]\n";
for ($yy = 0; $yy < 300; $yy++) {
$psStored{$xx,$yy} = $s; # Here I join all elements and store them as a string.
#push( @{$psStored[$xx][$yy]}, @elems );
}
}
使用严格;
使用警告;
我的($xx,$yy)#坐标变量
我的(@elems);#存储在每个矩阵位置上的元素数组
#生成3000个浮点值的数组。
#该列表将添加到每个数组元素中。照原样
#当然,每个元素都有一个完全不同的值列表。
#为了简单起见,这里我使用相同的值列表。
对于($xx=1;$xx<3000;$xx++){
推送(@elems,1+xx美元/10000);
}
#用生成的数组填充每个矩阵元素
我的%s存储;
我的$s;
$s=join('=',@elems);
对于($xx=0;$xx<300;$xx++){
打印“行[$xx]\n”;
对于($yy=0;$yy<300;$yy++){
$psStored{$xx,$yy}=$s;#这里我将所有元素连接起来,并将它们存储为字符串。
#推送(@{$psStored[$xx][$yy]},@elems);
}
}
你的意思是GB(字节)而不是GB(位),对吗?你能告诉我们这个脚本使用的8GB中的大部分是为什么分配的吗?是很多小块还是几个大块?知道它在mo上要分配多少内存吗
open my $ps_full_input, '<', 'fullPsIn.dat' or die $!;
my $aref;
push @{ $aref }, 1, 2, 3;
my $aref;
$aref = [];
push @{ $aref }, 1, 2, 3;
use strict;
use warnings;
my ($xx,$yy); # Coordinate variables
my (@elems); # Array of elements to be stored on each matrix position
# Generate an array of 3000 floating point values.
# The list will be added to each array element. In the true script
# of course, each element has a list of completely different values.
# Here I use the same list of values for simplicity.
for ($xx = 1; $xx < 3000; $xx++) {
push( @elems, 1+$xx/10000 );
}
# Fill in each matrix element with the generated array
my %psStored;
my $s;
$s=join('=',@elems);
for ($xx = 0; $xx < 300; $xx++) {
print "Row [$xx]\n";
for ($yy = 0; $yy < 300; $yy++) {
$psStored{$xx,$yy} = $s; # Here I join all elements and store them as a string.
#push( @{$psStored[$xx][$yy]}, @elems );
}
}