Perl在对象销毁时不会调用DESTROY的情况?

时间:2012-05-08 19:20:41

标签: perl

这是我的同事所面临的一个令人困惑的问题。而且我也无法解决问题。

在他编写的类中,简短版本定义了DESTROY析构函数/方法,当对象被销毁时,DESTROY不会被调用。在我们认为对象超出范围的时刻,它不会被调用。虽然我们认为可能在某处有悬挂引用它,但它也不会在脚本退出时被调用。我们使用调试print语句来填充类和脚本,甚至在END块中明确调用它只是为了验证我们没有以某种方式将它放入错误的命名空间。 (我们没有。显式调用按预期触发了所有print语句。)

所以我对此感到困惑,并且他对答案的兴趣与他一样。什么情况可能导致这种行为?有问题的脚本正在彻底退出 - 没有调用POSIX::_exit或类似的东西。唯一的变量"这是因为该类正在使用Class::MethodMaker来定义一些访问器和构造函数。但是,Class::MethodMaker文档中没有引用与类DESTROY方法进行交互(或覆盖)。

3 个答案:

答案 0 :(得分:6)

没有看到代码,就无法知道出了什么问题。但是我可以想象一下这样一种场景:看起来你的DESTROY()方法没有被调用:

#!/usr/bin/perl

use strict;
use warnings;

sub DESTROY {
    die {};
    print "DESTROY\n";
}

{
    print "creating object...\n";
    my $obj = bless {};
    print "it goes out of scope...\n";
}

print "object is out of scope\n";

此脚本打印:

creating object...
it goes out of scope...
object is out of scope

可能错误并不像本例中那么明显。 die()调用可以在DESTROY代码中深入。

die()调用可能是由您没有想到的某些条件引起的。在全局破坏期间,对象以任意顺序未定义:

#!/usr/bin/perl

use strict;
use warnings;

sub DESTROY {
    die {} if ! defined $_[0]->[0];
    print "$_[0]->DESTROY()\n";
}

print "creating objects...\n";
my $x = bless [];
my $y = bless [$x];
$x->[0] = $y;
print "before global destruction...\n";

循环引用并非必须发生这种情况。其中一个对象检查它是否可以访问另一个对象。如果访问失败,则抛出异常。

h2h,Matthias

答案 1 :(得分:6)

还有另一种方式没有调用DESTROY,这种方式没有特别清楚地记录下来。如果您正在编写守护进程等,它只会影响您。基本上,如果您的进程因信号而死(甚至CTRL-C,实际上是SIGINT),那么它将不会调用DESTROY方法。你可以通过使用一个只调用exit()的信号处理程序来实现它。在下面的示例中,如果程序正常退出,或者收到SIGTERM,则调用DESTROY()方法:

sub _signal_handler {
  exit(0);
}

sub new {
  my ($class) = @_;
  my $self = {};
  bless $self, $class;
  SIG{'TERM'} = \&_signal_handler;
  return $self;
}

sub DESTROY {
  my ($self) = @_;
  print "Destroy method called\n";
}

答案 2 :(得分:1)

仅发现一个类中的多个DESTROY子对象也可能导致这种情况,看起来只有最后一个实例被调用了。