我正在尝试做一个与此等效的 XS:
package RefTestPP;
use strict;
use warnings;
sub new {
my ($class, $self) = (@_, {});
return bless $self, $class;
}
1;
这种构造函数应该在调用时“自动激活”它的基础RefTestPP->new()
,或者使用给定的引用作为基础,比如RefTestPP->new({ stuff => 123 });
.
但是,我遇到了无法解释的泄漏。这是我的RefTest.xs
文件:
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
MODULE = RefTest PACKAGE = RefTest
PROTOTYPES: ENABLE
void
new(sclass="RefTest", base=sv_2mortal(newRV_noinc((SV *) newHV())))
const char *sclass
SV *base
PREINIT:
HV *stash;
PPCODE:
stash = gv_stashpv(sclass, 0);
ST(0) = sv_bless(base, stash);
XSRETURN(1);
void
new_leaky(sclass="RefTest", base=newRV_noinc(sv_2mortal((SV *) newHV())))
const char *sclass
SV *base
PREINIT:
HV *stash;
PPCODE:
stash = gv_stashpv(sclass, 0);
ST(0) = sv_bless(base, stash);
XSRETURN(1);
RefTest.t
以及检测泄漏的文件:
use strict;
use warnings;
use Devel::Leak;
use Test::More;
BEGIN { use_ok('RefTest') };
sub test_leak (&$;$) {
my ($code, $descr, $maxleak) = (@_, 0);
my $n1 = Devel::Leak::NoteSV(my $handle);
$code->() for 1 .. 1000;
my $n2 = Devel::Leak::CheckSV($handle);
cmp_ok($n1 + $maxleak, '>=', $n2, $descr);
}
# OK
test_leak { my $ref = RefTest->new() or die }
'first sv_2mortal(); then newRV_noinc()', 2;
# also OK
test_leak { my $ref = RefTest->new_leaky({}) or die }
'first sv_2mortal(); then newRV_noinc(); pre-init base', 2;
# leaks!
test_leak { my $ref = RefTest->new_leaky() or die }
'first newRV_noinc(); then sv_2mortal()', 2;
done_testing 4;
(正确编译所需的其余文件是由 生成的默认文件h2xs -A -n RefTest
)
重点是:
- 作为参数传递给构造函数的基引用永远不会泄漏;
- 在XS 代码中创建的基础
sv_2mortal(newRV_noinc((SV *) newHV()))
也不会泄漏; - 使用创建的 base
newRV_noinc(sv_2mortal((SV *) newHV()))
将泄漏(并最终Attempt to free unreferenced scalar: SV 0xdeadbeef
在全局销毁期间导致臭名昭著的消息)。
sv_2mortal(newRV_noinc(...))
有什么不同的理由newRV_noinc(sv_2mortal(...))
吗?我只是做错了吗?