Perl死于:“用法:全局销毁期间DBD :: Pg :: db :: DESTROY(dbh)”

时间:2013-02-22 17:50:36

标签: perl postgresql dbd dbd-pg

在生产中运行的稳定的,基于Web的单线程/进程perl应用程序开始间歇性地抛出此错误,并且仅在系统负载很重的情况下。我们无法确定根本原因。

Usage: DBD::Pg::db::DESTROY(dbh) during global destruction

有人可以提供此错误的任何解释吗?当Perl在关闭之前进行清理时,在没有参数(self?)的情况下调用DESTROY时,它似乎是从Pg.sx抛出的。 (我通过谷歌在较旧的源代码中看到该消息,但在我们的版本中没有。)我们的环境:

  • 操作系统:FreeBSD 8.3-STABLE
  • Perl v5.14.2
  • DBD :: Pg v2.19.3
  • PostgreSQL:v9.2.3

2 个答案:

答案 0 :(得分:2)

这是一个黑暗中的镜头。

DBI数据库句柄通常像任何其他对象一样被销毁 - 当没有任何引用它们时。但是,事情可以防止手柄自然被破坏:

  • Handle是一个全局包
  • 句柄是Perl无法自动释放的循环引用的一部分

当发生这种情况时,对象会被破坏,作为“全局破坏”的一部分,它基本上只是取消所有内容并调用DESTROY,实际上是一个随机顺序。这可能是造成虚假错误的原因。

首先,您可以尝试在脚本的开头和结尾处枚举数据库句柄,并查看是否仍然有人在最后使用它们。见this code snippet

sub show_child_handles {
    my ($h, $level) = @_;
    printf "%sh %s %s\n", $h->{Type}, "\t" x $level, $h;
    show_child_handles($_, $level + 1)
        for (grep { defined } @{$h->{ChildHandles}});
}

my %drivers = DBI->installed_drivers();
show_child_handles($_, 0) for (values %drivers);

如果您不确定该对象为何仍在使用中,您可以在某些大型数据结构上使用Devel::Cycle来查找它们。

您可能还会发现DBI的tracing functionality很有用。在运行脚本之前导出DBI_TRACE=2,每次创建或销毁句柄时都会记录它。

答案 1 :(得分:1)

在我的情况下,它在升级服务器后开始发生,因此它似乎是PostgreSql / Perl / DBD特定版本的错误。

在我没有明确销毁数据库句柄的所有脚本中突然出现此错误。 添加$dbx->disconnect()解决了它。

更新:此解决方法仅在我的某些脚本中修复了错误。在其他情况下,当明确地破坏数据库句柄时,错误仍然存​​在。