5

我有一个长的 perl 脚本,它将文件中的一些信息缓存在哈希中,每隔一段时间(这里,每 100000 个位置),它会打印该窗口的哈希值,然后尝试删除大部分哈希中的内容,除了要在下一次迭代中使用的小缓冲区。

我说它试图删除内容,因为我的脚本在内存使用中爆炸,直到它使用所有内存并崩溃。尽管删除语句似乎将散列中的键数量(请参见下面的打印 STDERR)减少到只有少量元素,但脚本的内存消耗却猛增,就好像它没有删除内容一样。如果我注释掉 delete 语句,它使用相同数量的内存,唯一的区别是迭代需要更长的时间。似乎删除命令后键的数量减少了,但值的数量没有减少。

我确保结果的读取和输出没有奇怪的缓冲。事实上,如果我只是注释掉使用 %hash 的地方,脚本并不会耗尽内存,因此我将其范围缩小到填充和删除 %hash 中的条目。

我也尝试使用 hashref 而不是 %hash,同样的情况仍在发生。

怎么会在记忆中炸裂?我在这里遗漏了什么明显的东西吗?

my %hash;
# while ( Read from input ) {
# Fill hash here and there with: $hash{$this_p}{$this_c}++
# ...
# Then every 100000 entries
 if ( not $pos % 100000 ) {
    print STDERR "pre ", scalar %hash , "\n";
warn total_size(\%hash);
    for my $p ( sort { $a <=> $b } keys %hash ) {
        last if ( $p > $max_possible{$subset} );
        if ( $p + $buffer < $pos ) {
            print $out "$p\t";
            for my $c ( keys %{ $hash{$p} } ) {
                print $out "$c ". $hash{$p}{$c} . ";";
            }
            print $out "\n";
            delete $hash{$p};
        }
    }
    print STDERR "post ", scalar %hash , "\n";
warn total_size(\%hash);
  }
#}

输出是这样的:

pre 322484/524288
134297952 at /home/
post 681/524288
4368924 at /home/av
pre 681/524288
4368924 at /home/av
post 681/524288
4368924 at /home/av
pre 681/524288
4368924 at /home/av
post 681/524288
4368924 at /home/av
pre 629257/1048576
260016542 at /home/
post 344/1048576
8477509 at /home/av
pre 1903885/4194304
689633878 at /home/
post 900/4194304
33790436 at /home/a
[...]

这是在 64 位 Linux 机器上使用 perl v5.14.2。

4

1 回答 1

6

随着程序运行,您在每次传递中放置在散列中的元素数量正在增加。0+keys(%hash)会告诉你确切的数字,但下面的分子会相似(但更低)

                      322484 added
pre  322484/524288
                      321803 cleared (99.8% of added)
post    681/524288
                           0 added
pre     681/524288
                           0 cleared (100.0% of added)
post    681/524288
                           0 added
pre     681/524288
                           0 cleared (100.0% of added)
post    681/524288
                      628576 added
pre  629257/1048576
                      628913 cleared (100.0% of added)
post    344/1048576
                     1903541 added
pre 1903885/4194304
                     1902641 cleared (100.0% of added)
post    900/4194304

分母只是在增长,因为分子在增长。这不相关。这不是累积增长。即使您每次都有新的哈希值,它也会变得那么大。

分子只会增长,因为您添加到哈希中的元素数量会增长。如您所见,清除代码的效果非常好。

这看起来根本不像是内存泄漏。看起来您实际上正在使用内存。也许您应该更频繁地清除它?

代替

if (not $pos % 100000) {
    ...
}

利用

if (keys(%hash) >= 1_000_000) {
    ...
}

或者,如果您想要定期反馈,

if (++$since_last >= 100_000 || keys(%hash) >= 1_000_000) {
    $since_last = 0;
    ...
}

根据需要调整限制。

于 2013-08-13T16:05:38.907 回答