首先 - 这不是我的代码 - 代码存在问题,我试图找出如何调试问题。如果我有机会的话,我会对代码进行大量的更改(过多的大括号,全局变量,使用连接函数而不是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字节宽。
我想到的事情:
undef
变量上调用$output
将释放它正在使用的内存,对吗?如果它没有,那可能是存在内存问题的另一个地方。@row
变量正在使用的内存将被重用(?),对吗?如果没有,我可以看到使用全局数组存储每一行可能会耗尽内存。我希望有一些明显的东西,我只是不理解。如果通过查看代码没有明显的东西,我可以使用哪些技术来调试这个问题?
提前致谢!
答案 0 :(得分:3)
可能是您(可能是无意中)缓存了太多行。您可以通过查看$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>.
答案 1 :(得分:0)
增加trace level,并在Perl和GDB调试器下运行代码。您需要找出过程失控的确切位置。
如果您没有运行相关模块和数据库的最新版本,请考虑您找到已修复的旧错误的可能性。
答案 2 :(得分:0)
就#1而言,我相信它会将整个结果加载到内存中 编辑:我记得这是DBI中的一个选项
对于#2和#3,您应该将变量本地化到它们所使用的范围。
我怀疑你执行后实际上已经没有内存了,不过我知道你说不然。您似乎不太可能在该循环中耗尽大量内存。当然除非ROWOUT实际上是对内存中变量的引用,但我们不知道如果你没有提供完整的脚本。