2013-01-10 35 views
2

我有一個對象,我做了很多東西,然後通過調用一個TidyUp()方法來完成,該方法顯示關於發生了什麼的一些統計信息。Perl檢測DESTROY作爲結果死()

作爲內部測試的一部分,我想要檢測何時這些對象正在創建,但在程序退出之前未被整理,並且在那種情況下死亡。

所以我給TidyUP()中設置的對象添加了一個標誌,如果這個標誌沒有設置,那麼這個類的DESTROY子例程會死掉。

這一切都很好,但它有一個不幸的副作用。如果程序中出現其他問題,導致死亡被調用,那麼全球破壞就會引發我的DESTROY,它注意到物體尚未被整理並死亡。問題是我在這一點上失去了原來的死信息。

所以我想檢測是否由於死亡或者正常程序退出而發生了破壞,只有在後一種情況下添加我的新死亡。

我看了一下Detecting global destruction in Perl,但我不認爲這有幫助,因爲我想檢測什麼觸發了全球性破壞。

+0

使用Devel :: Leak? – ikegami

+0

或END塊? – ysth

+0

進一步檢查發現死信息正在消失 - 這是在我寫出有關未整理對象的信息之前。但是,我仍然希望跳過未整理的對象檢查 - 我會檢查$?一試... –

回答

0

您可以在檢查對象是否整理之前設置全局標誌。然後你知道你的程序在哪個階段運行。當您的程序使用$SIG{__DIE__}去死時,您也可以嘗試註冊回調。檢查$?是不安全的,因爲它可以通過其他方式設置。檢查你是否在全球破壞也應該工作。但最簡潔的解決方案是將所有需要整理的對象存儲在一個額外的數組中。然後,您可以隨時循環使用這些對象,並取消使用DESTROY

0

從這個問題來看,我發現DESTROY方法中的調用堆棧略有不同,這取決於程序如何退出。也許這可以幫助:

package Foo; 
sub new { bless [], __PACKAGE__ } 
sub DESTROY { 
    my ($n,$pkg,$file,$line); 
    while (my @c=caller($n++)) { 
     ($pkg,$file,$line) = @c; 
    } 
    print STDERR "DESTROY called via $file line $line\n"; 
} 
my $foo = Foo->new; 
if ($ARGV[0] eq 'die') { die }  # line 11 
if ($ARGV[0] eq 'exit') { exit }  # line 12 
# else passive exit 

$ perl 14255585.pl die 
Died at 14255585.pl line 11. 
DESTROY called via 14255585.pl line 11 

$ perl 14255585.pl exit 
DESTROY called via 14255585.pl line 12 

$ perl 14255585.pl foo 
DESTROY called via 14255585.pl line 0 

如果進出點在程序列表中是小的和明確的,你可以只列舉他們和程序結束時處理它們。否則,你可以做一些即時的靜態代碼分析,看看死亡的可能原因是什麼。

0

您可以掛接到$SIG{__DIE__},全球異常處理程序:

#!/usr/bin/perl 
use Modern::Perl; 

package Foo; 
my $DIED = 0; 
BEGIN { $SIG{__DIE__} = sub { $DIED = 1 }; } 

sub new { bless [0] } 
sub DESTROY { die 'untidy' unless shift->[0] or $DIED } 
sub tidy_up { shift->[0] = 1 } 

package main; 
my $foo = new Foo; 
die if @ARGV; # line 13 
$foo->tidy_up(); 
say 'success'; 

$ perl test.pl 
success 

$ perl test.pl die 
Died at test.pl line 13. 

自認爲異常處理程序是全球的裝機量,確保您不會覆蓋現有的錯誤處理程序。 Signals::XSIG有幫助。