Perl: Почему Devel:: Refcount:: refcount и Devel:: Peek:: SvREFCNT не согласны?
Я читал Как мне получить доступ к счету хэша Perl?, и там предлагаются как Devel::Refcount::refcount
, так и Devel::Peek::SvREFCNT
.
Но они не возвращают одинаковые подсчеты ссылок. Почему это?
Здесь представлен измененный пример из perldoc Devel::Refcount
:
use Devel::Peek;
use Devel::Refcount;
my $anon = [];
printf "Anon ARRAY $anon has %d/%d reference\n",
Devel::Refcount::refcount($anon),
Devel::Peek::SvREFCNT($anon);
my $otherref = $anon;
printf "Anon ARRAY $anon now has %d/%d references\n",
Devel::Refcount::refcount($anon),
Devel::Peek::SvREFCNT($anon);
который печатает:
Anon ARRAY ARRAY(0x8b10818) has 1/1 reference
Anon ARRAY ARRAY(0x8b10818) now has 2/1 references
Обратите внимание на последнее несоответствие 2/1...
(Если окажется, что я не делаю что-то глупое, я добавлю ссылку из Как мне получить доступ к количеству ссылок хеша Perl? здесь)
Ответы
Ответ 1
Я не могу сказать, что все это еще не понял, но на ваш вопрос ответственно видно на Devel::Refcount
perldoc
СРАВНЕНИЕ С SvREFCNT
Эта функция отличается от Devel:: Peek:: SvREFCNT тем, что SvREFCNT() дает ссылочный счет самого SV-объекта, который он передал, тогда как refcount() дает счетчик объекта, на который указывает. Это позволяет ему также подсчитывать количество ссылок (например, ARRAY, HASH, CODE, GLOB и Regexp).
Рассмотрим следующую примерную программу:
use Devel::Peek qw( SvREFCNT );
use Devel::Refcount qw( refcount );
sub printcount
{
my $name = shift;
printf "%30s has SvREFCNT=%d, refcount=%d\n",
$name, SvREFCNT($_[0]), refcount($_[0]);
}
my $var = [];
printcount 'Initially, $var', $var;
my $othervar = $var;
printcount 'Before CODE ref, $var', $var;
printcount '$othervar', $othervar;
my $code = sub { undef $var };
printcount 'After CODE ref, $var', $var;
printcount '$othervar', $othervar;
Это приводит к выходу
Initially, $var has SvREFCNT=1, refcount=1
Before CODE ref, $var has SvREFCNT=1, refcount=2
$othervar has SvREFCNT=1, refcount=2
After CODE ref, $var has SvREFCNT=2, refcount=2
$othervar has SvREFCNT=1, refcount=2
Здесь мы видим, что SvREFCNT() подсчитывает количество ссылок на объект SV, переданных в качестве скалярного значения - $var или $othervar соответственно, тогда как refcount() подсчитывает количество опорных значений, которые указывают на референт object - анонимный ARRAY в этом случае.
Перед созданием ссылки CODE оба $var и $othervar имеют SvREFCNT() из 1, поскольку они существуют только в текущей лексической панели. Анонимный ARRAY имеет refcount() из 2, потому что как $var, так и $othervar хранят ссылку на него.
После создания ссылки CODE переменная $var теперь имеет SvREFCNT() из 2, поскольку она также появляется в лексической панели для нового анонимного блока CODE.
Ответ 2
Devel::Refcount::refcount($anon)
возвращает счетчик ссылок, на который ссылается $anon
.
Массив ссылается на $anon
и на $otherref
: 2
Devel::Peek::SvREFCNT($anon)
возвращает счетчик ссылок $anon
.
Скаляр ссылается на пэд, в котором он находится: 1
Devel:: Peek, похоже, не предоставляет средства для подсчета количества массивов, хэшей и т.д.
$ perl -MDevel::Peek -E'my $aref2 = my $aref1 = []; Dump($aref1);'
SV = IV(0x99eee34) at 0x99eee38
REFCNT = 1 <---- Devel::Peek::SvREFCNT
FLAGS = (PADMY,ROK)
RV = 0x99d57d0
SV = PVAV(0x99d6778) at 0x99d57d0
REFCNT = 2 <---- Devel::Refcount::refcount
FLAGS = ()
ARRAY = 0x0
FILL = -1
MAX = -1
ARYLEN = 0x0
FLAGS = (REAL)
Perl предоставляет полупоставленный встроенный модуль Internals::SvREFCNT
, который работает на скалярах, массивах и хешах.
Internals::SvREFCNT(@$anon)
возвращает счетчик ссылок < <29 > .
Массив ссылается на $anon
и на $otherref
: 2
Вышеуказанное работает только для скаляров, массивов и хешей, и вам нужно использовать правильную сигилу. Если вы просто хотите передать произвольную ссылку, вы можете использовать:
&Internals::SvREFCNT($anon) + 1
возвращает счетчик ссылок, на который ссылается $anon
.
Массив ссылается на $anon
и на $otherref
: 2