簡體   English   中英

識別Perl / DBI代碼中的內存問題

[英]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字節寬。

我想到的事情:

  1. DBI的fetchrow_array函數足夠聰明,不能將完整的數據集拉入內存,對嗎? 我的假設是數據在數據庫上,並且fetchrow_array一次檢索一行,所以即使你有100億行,你也不應該有內存問題 - 這是正確的嗎?
  2. $output變量上調用undef會釋放它正在使用的內存,對嗎? 如果沒有,那可能是存在內存問題的另一個地方。
  3. @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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM