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