Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding newRV_inc vs newRV_noinc

Tags:

perl

perlguts

In trying to deal with references at the C level I can't seem to figure out the difference (in practice) between newRV_inc and newRV_noinc. To that end I have mocked up this little Inline::C example.

#!/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_noinc();
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

gives:

inc: 1
noinc: 1

Can anyone help me understand why this code behaves this way?

like image 799
Joel Berger Avatar asked Jul 17 '11 19:07

Joel Berger


1 Answers

When you call SvREFCNT($arrayref) you're getting the reference count of the arrayref, not the array that it's referencing. newRV_inc increments the reference count of array, and newRV_noinc doesn't. But that doesn't make any difference to the reference count of arrayref. (I don't think you can get at the refcount of the array referenced by an arrayref with Devel::Peek.)

Have you read the example in perlguts: Reference Counts and Mortality?

AV* array = newAV() creates a new array with a refcount of 1. In make_arrayref_inc, newRV_inc increments that to 2 while creating a new SV (the arrayref) with a refcount of 1. This causes a memory leak, because you don't decrement array's refcount before exiting the function. Perl thinks it has 2 references, but it really only has 1, so it will never be garbage collected until the interpreter shuts down.

That's why you normally use newRV_noinc in code that returns a reference to a newly created value. It's more efficient than using newRV_inc and then SvREFCNT_dec. You can think of newRV_noinc as transferring ownership of the AV from array to arrayref.

like image 197
cjm Avatar answered Oct 20 '22 19:10

cjm