Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Re: perlembed: mortalize an AV, get "Attempt to free unreferenced scalar" - don't mortalize, leaks memory

by demerphq (Chancellor)
on Jul 10, 2006 at 11:09 UTC ( #560111=note: print w/ replies, xml ) Need Help??


in reply to perlembed: mortalize an AV, get "Attempt to free unreferenced scalar" - don't mortalize, leaks memory

So I'm not supposed to mortalize the scalars that I push onto the array? Why is that? It makes my problem disappear, which I like, but I don't understand it, which I don't like. Any further thoughts are appreciated.

When an object is freed due to its refcount going to 0 all the items that object references have their refcount decremented in turn. So if you stuff an AV with mortalized SV'es the SVes could be freed before the AV itself tries to do the refcount decrement on the scalars it contains. Which then raises a warning as this kind of thing (at least from the perl side point of view) shouldn't happen.

So if you think about what happens in:

my @x; # @x has a refcount of 1 { my @array=(\@x); # @x has a refcount of 2 } # Free lexicals # @x has a refcount of 1

Its a recursive process:

procedure refcount_dec(item) if ( --item.refcount == 0 ) foreach sv in item.contents refcount_dec(sv) endfor if ( item.isref ) refcount_dec(item.references) endif endif endproc
---
$world=~s/war/peace/g


Comment on Re: perlembed: mortalize an AV, get "Attempt to free unreferenced scalar" - don't mortalize, leaks memory
Select or Download Code
Re^2: perlembed: mortalize an AV, get "Attempt to free unreferenced scalar" - don't mortalize, leaks memory
by edan (Curate) on Jul 10, 2006 at 11:47 UTC

    Thanks for the reply demerphq. But I think you've confused me more.

    I thought my mortalized SVs were only supposed to be blown away when the following code gets executed:

    FREETMPS; LEAVE;

    So how could the values be freed too soon?

    Also, if what you say is true, then I'd think it would hold true for storing values in a hash, too. But I experimented, and it seems like there, I have to mortalize the SVs I am storing in the hash, or there's a leak:

    HV *hash = (HV *)sv_2mortal((SV *) newHV()); SV *type = newSVpv("string", 0); //SV *type = sv_2mortal(newSVpv("string", 0)); SvREFCNT_inc( type ); if ( NULL == hv_store( hash, "type", strlen("type"), type, 0) ) { SvREFCNT_dec( type ); printf("hv_store failed\n"); exit(1); } XPUSHs(sv_2mortal(newRV((SV *)hash)));

    That leaks, but if I mortalize the SV as in the comment, everything is great, and there are no warnings. So what gives? What's the difference between the av_push and hv_store examples?

    Thanks

    --
    edan

      Update: Looks like this isnt right... Sigh

      I thought my mortalized SVs were only supposed to be blown away when the following code gets executed:

      Yes, the logic i explained is basically what happens when FREETMPS/LEAVE occurs. Dont take my description too literally, im far from being authority on the internals, just trying to add some insight based on the little understanding i do have.

      So how could the values be freed too soon?

      Im assuming the reason the vars could be blown away too soon is that when you mortalize a var it goes on a temps stack, which is then processed by the FREETMPS/LEAVE macros. If you mortalize a member element of a composite structure which is itself mortalized then presumably there will be two attempts to refcount-dec/free the same thing.

      That leaks, but if I mortalize the SV as in the comment, everything is great, and there are no warnings. So what gives? What's the difference between the av_push and hv_store examples?

      Im basically guessing, but id think the problem is that when you do newSVpv() the created SVPV has a refcount of 1. You then increment the refcount, bringing it to 2, (note that in the array example you do not do the additional SvREFCOUNT_inc()) then you hv_push into a mortalized hash, which is then referenced by a mortal SVRV. So the mortal SVPV gets its refcount decremented once by its own mortalization, and then decremented again when the hash is freed. If you dont mortalize the SVPV then its refcount is 1 and it leaks. However it seems to me that the proper thing to do here is to do something like:

      HV *hash = newHV(); SV *type = newSVpv("string", 0); if ( NULL == hv_store( hash, "type", strlen("type"), type, 0) ) { SvREFCNT_dec( type ); /* free the SV */ printf("hv_store failed\n"); exit(1); /*me wonders about this...*/ } XPUSHs(sv_2mortal(newRV((SV *)hash)));

      The idea being that the only thing that needs to be mortal is the newRV(), which when its freed will cascade through the things it references, refcount decrementing them to 0 and thus causing them to be freed.

      Anyway, its very possible ive gotten something horribly wrong, but this is more or less as i understand it.

      ---
      $world=~s/war/peace/g

        Tried that. Leaks like a madman. Nope, I think the HV and the SVpv need to be mortal. I'll stick with my current incantation, since empirically it's correct, even though I still don't know why, and am still plagued by the thought that maybe it only seems right, but isn't.

        Any more help is most welcome.

        --
        edan

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://560111]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (16)
As of 2014-10-30 14:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (208 votes), past polls