如何调查“尝试释放未引用的标量”

时间:2011-07-27 17:10:34

标签: perl debugging

Perl脚本(使用大量本地编写的模块,正在积极开发中)刚刚开始生成零星的

“尝试释放未引用的标量:SV 0xa6e685c,Perl解释器: 全局破坏期间的0x96d9008。“

消息。这总是可重复的,因为特定的命令序列总是产生消息,但是我没有设法隔离出一个简单的或独立的案例来引发它。特别是,从Perl调试器运行脚本时我还没有看到它(我可以在调试使用IPC :: Open3来运行目标脚本的脚本时得到它。)

我意识到这可能只是Perl中的一个错误,但更有可能是我正在做的事情,很可能是我对SVN :: Client的调用;但我很难找到一种方法来调查它,我想知道是否有人有任何指针。

Perl 5.10.0;各种版本的Fedora Linux。我将在Perl 5.12上尝试它,但除非它也在那里出现,否则它对我没有帮助。 编辑:在5.12中可靠地提供消息的特定情况不在5.12中。不幸的是,这并没有真正告诉我任何事情。

5 个答案:

答案 0 :(得分:2)

迟到的答案,但我写了一篇关于这个特定主题的长篇文章,应该有助于调试:The Dreaded "Attempt to free unreferenced scalar"

答案 1 :(得分:1)

这通常与线程问题有关,特别是在将变量从一个线程传递到另一个线程中运行的子例程时。这是模式的抽象示例:

<强> A.pl

....
my $dummy;
threads->create("B::c", ($dummy));
....

<强> B.pm

....
sub c{...}
....

我意识到在“加载本地编写的模块”中搜索类似于此的东西并不容易。也许你可以删除你的程序块,直到找到一些能改变行为的东西;这应该可以帮助你解决问题。

答案 2 :(得分:1)

我也经常遇到这些消息(在使用fork的代码中)和全局破坏阶段中的分段错误的相关问题(也就是说,程序可以正常完成,但在此过程中出错全局销毁可以使程序以非零退出代码退出。我也不知道这些问题是否可以修复,但它们通常可以解决。

首先,使用全局变量来检测您是否处于全局销毁阶段:

our $_GLOBAL_DESTRUCTION = 0;
END { $_GLOBAL_DESTRUCTION = 1; }

(另请参阅Perl v中可用的${^GLOBAL_PHASE}变量&gt; = 5.13.7)

然后避免在全局销毁阶段运行麻烦的代码:

sub MyObject::DESTROY {
    return if $_GLOBAL_DESTRUCTION;
    ... # else proceed 
}

sub other_function_that_frees_unreferenced_scalars {
    return if $_GLOBAL_DESTRUCTION;
    ...
}

答案 3 :(得分:0)

检查任何引用指针的typeglobs,例如散列哈希的类型。我遇到了一个用于在不同的数组散列之间切换的typeglob。使用typeglob和原始哈希名称删除条目时出现错误。使用没有嵌套的简单哈希或摆脱typeglob消除了这个问题。

答案 4 :(得分:0)

foreach (@var)是另一个很好的候选人。

以下代码给了我这个警告:

foreach (@list1) {
    my ($i, $j) = @$_;
    my $k = get_k($i, $j);
    foreach (@$k) {
        sub_that_uses_fork($_);
    }
}

但以下没有:

while (scalar(@list1)) {
    my ($i, $j) = @{shift(@list1)};
    my $k = get_k($i, $j);
    foreach (@$k) {
        sub_that_uses_fork($_);
    }
}