cre*_*ive 3 perl garbage-collection memory-leaks reference xs
我试图做一个相当于XS的XS:
package RefTestPP;
use strict;
use warnings;
sub new {
my ($class, $self) = (@_, {});
return bless $self, $class;
}
1;
Run Code Online (Sandbox Code Playgroud)
这种构造函数应该在被调用时"自动"它的基础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);
Run Code Online (Sandbox Code Playgroud)
以及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;
Run Code Online (Sandbox Code Playgroud)
(正确编译所需的其余文件是生成的默认文件h2xs -A -n RefTest
)
重点是:
sv_2mortal(newRV_noinc((SV *) newHV()))
也不泄漏;newRV_noinc(sv_2mortal((SV *) newHV()))
漏洞创建的base (最终Attempt to free unreferenced scalar: SV 0xdeadbeef
在全局破坏期间导致臭名昭着的消息).有什么理由sv_2mortal(newRV_noinc(...))
可以与众不同newRV_noinc(sv_2mortal(...))
吗?我只是做错了吗?
sv_2mortal
是一个延迟的refcount减量.(它发生在调用者有机会参考它或复制它之后.)在这篇文章中,我将给出引用计数,好像sv_2mortal
立即减少,但将使用星号("*")来表示这一点.
以下代码使引用变为临界:
sv_2mortal(newRV_noinc((SV*)newHV()))
Run Code Online (Sandbox Code Playgroud)
所以,
以下代码使哈希值变为临界值:
newRV_noinc(sv_2mortal((SV*)newHV()))
Run Code Online (Sandbox Code Playgroud)
所以,