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

iezvtpos  于 2023-10-24  发布在  Perl
关注(0)|答案(4)|浏览(182)

这是我一位同事遇到的一个令人困惑的问题,我也无法找出原因。
简短的版本是,在他写的一个类中,定义了DESTROY析构函数/方法,当对象被销毁时,DESTROY不会被调用。它不会在我们认为对象超出范围的时候被调用。虽然我们考虑到可能在某个地方有一个对它的悬挂引用,但它不会在脚本退出时被调用。我们在类和脚本中添加了调试print语句,甚至在END块中显式调用了它,只是为了验证我们没有以某种方式将它放在错误的名称空间中。(我们没有。显式调用按预期触发了所有print语句。)
所以我对此感到困惑,我和他一样对答案感兴趣。什么情况会导致这种行为?有问题的脚本正在干净地退出-没有调用POSIX::_exit或类似的东西。唯一的“变量”是类正在使用Class::MethodMaker来定义一些访问器和构造函数。然而,在Class::MethodMaker文档中没有提到与类DESTROY方法进行交互(或重写)。

tzcvj98z

tzcvj98z1#

如果没有看到代码,就无法知道哪里出了问题。但我可以想象一个场景,看起来你的DESTROY()方法没有被调用:

  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. sub DESTROY {
  5. die {};
  6. print "DESTROY\n";
  7. }
  8. {
  9. print "creating object...\n";
  10. my $obj = bless {};
  11. print "it goes out of scope...\n";
  12. }
  13. print "object is out of scope\n";

此脚本将打印:

  1. creating object...
  2. it goes out of scope...
  3. object is out of scope

这个错误可能不像这个例子那么明显,die()调用可能在DESTROY代码的深处。
die()调用可能是由一些你没有想到的条件引起的。对象在全局销毁过程中以任意顺序被定义:

  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. sub DESTROY {
  5. die {} if ! defined $_[0]->[0];
  6. print "$_[0]->DESTROY()\n";
  7. }
  8. print "creating objects...\n";
  9. my $x = bless [];
  10. my $y = bless [$x];
  11. $x->[0] = $y;
  12. print "before global destruction...\n";

循环引用并不是必须的,一个对象检查它是否可以访问另一个对象,如果访问失败,抛出一个异常。
h2h,马蒂亚斯

展开查看全部
zbdgwd5y

zbdgwd5y2#

还有另一种不调用DESTROY的方式,它没有特别明确的文档记录。它只会在你编写守护进程之类的时候影响你。本质上,如果你的进程因为一个信号而死亡,(即使是CTRL-C,实际上是SIGINT),那么它就不会调用DESTROY方法。你可以通过使用一个只调用exit()的信号处理程序来让它这样做。在下面的例子中,如果程序正常退出,或者如果接收到SIGTERM,则调用DESTROY()方法:

  1. sub _signal_handler {
  2. exit(0);
  3. }
  4. sub new {
  5. my ($class) = @_;
  6. my $self = {};
  7. bless $self, $class;
  8. SIG{'TERM'} = \&_signal_handler;
  9. return $self;
  10. }
  11. sub DESTROY {
  12. my ($self) = @_;
  13. print "Destroy method called\n";
  14. }
展开查看全部
gkn4icbw

gkn4icbw3#

刚刚发现在一个类中有一个以上的DESTROY子也会导致这种情况,看起来只有最后一个示例被调用。

9avjhtql

9avjhtql4#

exec的调用将不会调用Destroy:

  1. use strict;
  2. use warnings;
  3. sub DESTROY {
  4. print "DESTROY\n"; # never runs
  5. }
  6. {
  7. print "creating object...\n";
  8. my $obj = bless {};
  9. print "it goes out of scope...but doesn't call DESTROY:\n";
  10. exec('/bin/true');
  11. }
  12. print "object is out of scope\n"; # never runs

相关问题