2015-04-15 34 views
1

我正在做一些非常大的數據的圖形分析,我需要存儲特定圖形邊緣的所有分數。鑑於數據的大小,我需要將信息寫入磁盤,並且我試圖使用與DBM::Deep並列的散列。以下是基本設置:如何正確地將散列與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接口還是有更好的方法來編寫這種方法?

我會先發制人地說,很難提供一個示例文件來重現此問題,因爲腳本需要運行幾秒鐘才能發現泄漏(意味着文件必須至少有10萬行)。我希望有些東西會跳出來,但如果這些信息不夠,我會提供一個腳本和一些數據。我使用Perl v5.20.2和最新的DBM :: Deep,2.0011。

編輯:我已經簡化了代碼:

$match_pairs{$pair} = $score; 

,我也曾嘗試OO接口做一個簡單的鍵/值存儲,我看到相同的行爲。這似乎是一個錯誤,所以我會報告它。

+2

與您的問題完全無關,但您可能可以刪除除「push」行之外的所有行,並獲得相同的結果。 –

+1

@JimDavis我讀到了autovivication不能正確的使用DBM :: Deep,或者不管用,所以我使用'if(exists $ hash {key}){...}'語法來保證安全。 – SES

+0

我不知道。好吧! –

回答

1

我在相關的GH問題上回答了這個問題(謝謝你打開它!),但我會在這裏重複一遍。

是的,隨着時間的推移,RAM的數量會慢慢增加。當讀取/usr/dict/words作爲鍵入DBM :: Deep哈希(Ubuntu 14.04,Perl 5.22.0)時,每讀出30k字,我的RAM就上升了大約1k。我的猜測(沒有可重複的測試)是,這只是簿記DBM :: Deep需要跟蹤添加30k元素所需的額外數據級別。

正如我在這個問題的評論中提到的,如果有可重複使用的測試文件,我會很高興地進一步研究這個問題。