On Thu, Nov 28, 2002 at 11:45:13AM +0000, Richard Clamp wrote:
> On Wed, Nov 27, 2002 at 10:36:04PM +0000, Mark Fowler wrote:
> [reference counting] 
> > Could you, or anyone else, give me a pointer to where this kind of thing
> > is documented?
> 
> L<perlguts/Reference Counts and Mortality>, plus, if you're writing
> some XS and think that you're leaking something, you can always try
> Devel::LeakTrace (if the something is SVs) or valgrind (if the
> something is regular malloced blocks). 

I don't really understand this stuff, but piecing together what I know
and a re-skim of the perl docs and source, I *think* that the summary is

0: "things" (SV, AV, HV, (etc?)) are refcounted - when the refcount hits 0
   the "thing" is freed.

    (which effectively means that their memory gets marked for re-use, so
    you may not always see symptoms if you're prematurely freeing things.
    it's got all the potential problems of C if you call free() and then
    carry on accessing that memory)

but you need to return "things" from your code; and the things are pointers
that you, not your caller, owns, and so you are responsible for cleaning
them up. (like wanting to return a pointer to malloc()ed space from a C
function). Except that they need cleaning up some point after your code
has returned.

1: "mortal" describes a system for flagging a value for a deferred cleanup.
   If you tell perl to make something "mortal", all it does is record on
   a TODO list that the "thing" (SV, AV, HV, etc) should have its reference
   count decreased by 1 at some later time. The later time corresponds to
   "end of statement", ie C<;> in your perl script, or when C code runs
   the macro FREETMPS; (defined in scope.h, calls Perl_free_tmps in scope.c)

   Not all temporaries are freed; the stack of TODOs can have markers placed
   on it to nest scopes, so processing is only for things mortalized since
   the last marker was placed (using the ENTER; macro)

   mortal doesn't mean automatically freeing something at scope exit; all it
   does is decrease the reference count by 1. Things get freed (as a side
   effect) if this decrease drops their reference count to zero. One
   implication of this is that you can mark something as mortal more than
   once - this just means it will get 1 future reference count decrease per
   time you marked it.

2: aggregates such as references, AVs and HVs "own" a reference count on each
   SV that they contain. So when their reference count drops to 0, they
   relinquish ownership of all their contents, by decreasing each item's
   reference count by one

[someone check this, please:]
3: so this means if you're returning a reference to an array or hash from
   your XS code, you only need to mark the top level reference as mortal; when
   that things reference count drops to zero, everything it owns is dropped
   by one. (I believe that this means the example on page 366 of Advanced
   Perl Programming is wrong - it makes everything it pushes into an array
   mortal)

4: If you still own a pointer to something, because it's static and meant
   to persist between calls to your routine, then you don't mortalise it.
   But you need to clean it up at some point.
   This is equivalent to returning a pointer to something you malloc()ed,
   but your C code retains "ownership" because at some future point you will
   free() it.

5: I believe that all the creation routines (newAV, newHV, the new SV
   routines) return you something with a refcount of 1. ie you have to do
   something with that reference, ie hold on to it and decrease it at your
   cleanup; give it away to someone else ("somebody else's problem"); or
   mark it mortal.

   All the add it to something routines (store in HV or AV) don't increase
   the refcount. They are assuming that you are giving them the reference.
   If they fail (you did check the return code, didn't you?) it's still your
   problem. [Perl_av_push() etc don't check]

   The sole exception to this is newRV, which is now an alias to the more
   descriptive newRV_inc, which creates a new SV holding a reference
   (ie that SV has a reference count of 1) plus increments the reference count
   of the thing you passed it. (being helpful, making an assumption)
   use newRV_inc() or newRV_noinc() to make your intent clear.

Nicholas Clark

Reply via email to