1

我正在对一些非常大的数据进行图形分析,我需要存储一组特定图形边的所有分数。鉴于数据的大小,我需要将信息写入磁盘,并且我正在尝试将绑定哈希与DBM::Deep一起使用。这是基本设置:

#!/usr/bin/env perl

use 5.010;
use strict;
use warnings;
use autodie;
use File::Spec;
use DBM::Deep;
use Cwd;

my $file = shift;
my $wd = getcwd();

open my $fh, '<', $file;

my %match_pairs;
my $dbm = File::Spec->catfile($wd, "pairs.dbm");
unlink $dbm if -e $dbm;

tie %match_pairs, 'DBM::Deep', { 
    file      => $dbm, 
    locking   => 1, 
    autoflush => 1, 
    type      => DBM::Deep::TYPE_HASH 
};

然后,我解析文件并将信息存储在某个分数阈值之上,如下所示($pair只是一个常规字符串):

if (exists $match_pairs{$pair}) {
    push @{$match_pairs{$pair}}, $score;
}
else {
    $match_pairs{$pair} = [$score];
}

此代码会产生内存泄漏,该泄漏会增加,直到您终止该进程。如果我注释掉这六行,就没有内存泄漏。奇怪的是,数据被写入了 DBM 文件,当我使用 DBM::Deep 或不使用时,我得到了相同的结果,所以看起来 tie 方法是正确的。我更改了日志模式、自动刷新、锁定和其他设置,我看到了相同的行为。

我在这里错误地使用 DBM::Deep 吗?例如,我应该使用 OO 接口还是有更好的方法来编写这个方法?

我会先发制人地说,很难提供一个示例文件来重现这个问题,因为脚本需要运行几秒钟才能注意到泄漏(这意味着文件必须至少有 100k 行)。我希望有些东西会跳出来,但如果信息不够,我会提供一个脚本和一些数据。我正在使用 Perl v5.20.2 和最新的 DBM::Deep, 2.0011。

编辑:我已将代码简化为:

$match_pairs{$pair} = $score;

而且我还尝试了 OO 接口做一个简单的键/值存储,我看到了相同的行为。看来这一定是一个错误,所以我会报告它。

4

1 回答 1

1

我在相关的 GH 问题中回答了这个问题(感谢您打开它!),但我会在这里重复一遍。

是的,随着时间的推移,RAM 的数量会慢慢增加。当/usr/dict/words作为键读入 DBM::Deep 哈希(Ubuntu 14.04,Perl 5.22.0)时,每读取 30k 个字,我的 RAM 就会增加约 1k。我的猜测(没有可重复的测试)是这只是 DBM::Deep 需要跟踪添加 30k 元素所需的额外数据级别的簿记。

正如我在本期评论中提到的那样,如果有一个可重复的测试文件我可以提交给该项目,我将很高兴进一步研究这个问题。

于 2015-06-17T04:14:23.230 回答