[英]Identify a memory problem in Perl/DBI code
首先 - 這不是我的代碼 - 代碼有問題,我試圖找出如何調試問題。 如果我有機會的話,我會對代碼進行大量的更改(過多的大括號,全局變量,使用連接函數而不是foreach等等)。 它充滿了不好的做法,但這不是我需要幫助的。
這是Perl代碼的片段(沒有子程序,沒什么特別的 - 基本上打開查詢結果的文件,執行查詢,並將結果轉儲到文件中):
# earlier in the program, @row, $field, and $output are all declared globally, like this:
my @row;
my $field;
my $output;
# a file is opened for output, with filehandle ROWOUT
# a database statement handle (DBD::DB2) is executed
while ( @{row} = ${sth}->fetchrow_array ) {
foreach ${field}( @{row} ) {
${field} =~ s/\s+$//;
${output} = "${output}\~${field}";
}
${output} =~ s/\~//;
print ROWOUT "${output}\n";
undef ${output};
}
在while循環的某個地方,Perl腳本崩潰了Out of Memory!
錯誤(不是一個干凈的崩潰 - 它只是停止與該消息一起運行。)
在大多數運行中,此查詢的卷非常小。 這次腳本崩潰時查詢的結果要大得多(仍然不大):150,000行,每行大約1200字節寬。
我想到的事情:
$output
變量上調用undef
會釋放它正在使用的內存,對嗎? 如果沒有,那可能是存在內存問題的另一個地方。 @row
變量使用的內存將在每次檢索到新行時重復使用(?),對嗎? 如果沒有,我可以看到如何使用全局數組存儲每一行可能會耗盡內存。 我希望有一些明顯的東西,我只是不理解。 如果通過查看代碼沒有明顯的東西,我可以用什么技術來調試這個問題?
提前致謝!
可能是您(可能是無意中)緩存了太多行。 您可以通過檢查$sth->{RowsInCache}
來了解已引入的$sth->{RowsInCache}
。 如果它是undef
,則沒有緩存,否則您將獲得行數。
您還可以通過以下方式重寫它來擺脫您必須使用$output
的體操:
while ( my @this_row = $sth->fetchrow_array ) {
# Get rid of this line once you figure out your memory problem.
print STDERR "Using ", ($sth->{RowsInCache} || 0), " rows in cache\n";
print ROWOUT join('~', map { s/\s+$// } @this_row), "\n";
}
因此,假設您的緩存中有太多行,您可以通過以下方式限制它:
my $dbh = DBI->connect($dsn, $user, $pass, { RowCacheSize => 20 })
or die "Cannot connect to $dsn: $DBI::errstr\n";
在DBI文檔中,您可以使用以下值控制緩存(假設您的驅動程序支持它):
0 - Automatically determine a reasonable cache size for each C<SELECT>
1 - Disable the local row cache
>1 - Cache this many rows
<0 - Cache as many rows that will fit into this much memory for each C<SELECT>.
提高跟蹤級別 ,並在Perl和GDB調試器下運行代碼。 您需要找出過程失控的確切位置。
如果您沒有運行相關模塊和數據庫的最新版本,請考慮您找到已修復的舊錯誤的可能性。
就#1而言,我相信它會將整個結果加載到內存中編輯:我記得這是DBI中的一個選項
對於#2和#3,您應該將變量本地化到它們所使用的范圍。
我懷疑你執行后實際上已經沒有內存了,盡管我知道你說不然。 您似乎不太可能在該循環中耗盡大量內存。 當然除非ROWOUT實際上是對內存中變量的引用,但我們不知道如果你不提供完整的腳本。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.