Понимание newRV_inc против newRV_noinc

При попытке справиться со ссылками на уровне C я не могу понять разницу (на практике) между newRV_inc а также newRV_noinc, С этой целью я издевался над этим маленьким Inline::C пример.

#!/usr/bin/env perl

use strict;
use warnings;

use Devel::Peek 'SvREFCNT';

my $arrayref_inc = make_arrayref_inc();
print "inc: ", SvREFCNT($arrayref_inc), "\n";

my $arrayref_noinc = make_arrayref_inc();
print "noinc: ", SvREFCNT($arrayref_noinc), "\n";

use Inline C => <<'END_C';
SV* make_arrayref_inc () {
  AV * array = newAV();
  SV * arrayref = newRV_inc((SV *)array);

  return arrayref;
}

SV* make_arrayref_noinc () {
  AV * array = newAV();
  SV * arrayref = newRV_noinc((SV *)array);

  return arrayref;
}
END_C

дает:

inc: 1
noinc: 1

Может кто-нибудь помочь мне понять, почему это ведет себя так?

1 ответ

Решение

Когда вы звоните SvREFCNT($arrayref) вы получаете счетчик ссылок на arrayref, а не массив, на который он ссылается. newRV_inc увеличивает счетчик ссылок array, а также newRV_noinc не делает. Но это не имеет никакого значения для подсчета ссылок arrayref, (Я не думаю, что вы можете получить на refcount массив, на который ссылается arrayref с Devel::Peek.)

Вы читали пример в perlguts: подсчет ссылок и смертность?

AV* array = newAV() создает новый массив с рефконтом 1. В make_arrayref_inc, newRV_inc увеличивает это значение до 2 при создании нового SV (arrayref) с refcount 1. Это вызывает утечку памяти, потому что вы не уменьшаете arrayПересчет перед выходом из функции. Perl считает, что у него есть 2 ссылки, но на самом деле есть только 1, поэтому он никогда не будет собирать мусор, пока интерпретатор не отключится.

Вот почему вы обычно используете newRV_noinc в коде, который возвращает ссылку на вновь созданное значение. Это более эффективно, чем использование newRV_inc а потом SvREFCNT_dec, Вы можете думать о newRV_noinc как передача права собственности на АВ от array в arrayref,

Другие вопросы по тегам