discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: bogus retain via NSEnumerator


From: Michael Ash
Subject: Re: bogus retain via NSEnumerator
Date: Tue, 20 Apr 2004 16:03:33 -0400

On Tue, 20 Apr 2004, Wayne Cochran wrote:

> Michael Ash <mike@mikeash.com> wrote in message 
> news:<20040417065133.U70764@agamemnon.twistedsys.net>...
>
> > To see *why* this is happening, consider what happens with an enumerator.
> > In order to make sure the enumerator functions correctly, it retains the
> > collection that it enumerates to ensure the collection doesn't get
> > deallocated before the enumerator is finished.
>
> This brings up a question -- what if you only need to enumerate through
> part of the container (e.g., searching for some item)? I am inferring that
> release messages are not sent to the container objects until the
> enumerator has exhausted all the elements.

Assume for a moment that you were writing NSEnumerator; how would you do
it?

This is what I would do: when created, the enumerator retains the array it
enumerates, so that bad things don't happen if you release the array
before you finish enumerating. When the enumerator reaches the end of the
array, or the enumerator is deallocated, whichever comes first, it
releases the array it was hanging on to. What I described is just a bit of
an optimization on top of this basic idea.

> No examples I see sends a release message to the enumerator, since (I assume)
> it has been autoreleased already by NSArray's objectEnumerator method.

Any object you get back from a method that's not "alloc", "copy", or
"retain" (plus the variants like mutableCopy) is autoreleased.

> >  What you're seeing looks
> > like a performance optimization; once the enumerator has reached the last
> > object, it no longer needs to keep the collection around, but it *does*
> > need to keep that last object around, so it releases the collection and
> > retains the object.
>
> That is indeed a strange behavior. I can not imagine a scenario where you
> only needed to hang on to the last object -- what does that buy you?

Imagine this:

NSArray *array = [[NSArray alloc] init....];
NSEnumerator *enumerator = [array objectEnumerator];
[array release]; // we're done with it, but the enumerator isn't

id obj;
while((obj = [enumerator nextObject]))
{
        ...do lots of work here...
}

Using the optimization I describe above, the array will get deallocated
before the last iteration of this while loop begins. Deallocating unneeded
memory earlier rather than later is always a good thing.

> > Once the enumerator is released, it will release the
> > object I'm sure, because otherwise there would be an enormous number of
> > posts saying "NSEnumerator leaks objects!"
>
> Your faith in these classes is strong. Perhaps, over time, I will reach that
> level of trust.

Run 'leaks' on any Cocoa program. You'll find a few leaks, but unless the
programmer screwed up something large, they'll all be one-time leaks that
happen at program startup. There are a lot of programs that use Cocoa
either directly or indirectly, and enumerators are extremely common; can
you imagine the havoc if every time you used an enumerator, you leaked an
object?

It helps to understand the purpose and design of the retain/release
system. The entire point of the system is to move decisions about memory
management from the global level "Is it safe to free this memory? Does
somebody have a pointer to it?" to the local level "Is it safe to
'release' this memory? Do *I* have a pointer to it?" With some exceptions,
it pulls this off pretty well. This is why you're not supposed to use the
-retainCount message unless you're debugging something; relying on it in
production code means you're making global decisions about object
lifetimes, which you're not supposed to do.

Apple lays down some basic rules for memory management and sticks with
them very consistently. If you alloc, copy, or retain an object, it's your
responsibility to send it exactly one release message for each alloc,
copy, or retain to balance. If you don't, it's not your responsibility,
either because you're being given an object that's cached or otherwise in
permanent residence, or because you're being given an autoreleased object.
Because of these rules, you shouldn't start worrying about extra retains
unless you discover that there's no balancing release; it's perfectly
legitimate, and happens fairly often, to retain an object behind
somebody's back just to ensure that it stays around as long as it's
needed.

It's not as easy as a garbage collector, but it makes sense once you get
used to it.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]