Re: Leaking Memory
Re: Leaking Memory
- Subject: Re: Leaking Memory
- From: mmalcolm crawford <email@hidden>
- Date: Fri, 24 Jan 2003 13:58:21 -0800
On Thursday, January 23, 2003, at 06:33 PM, Robert Goldsmith wrote:
Fundamentally, we are all nothing more than probability wave functions,
it looks very likely that the universe has 22 dimensions and time is a
figment of our imagination. This does not stop us pretending we exist,
feeling the universe is something that is happening elsewhere and time
is the most important thing there is.
Until we discover that the universe is composed of NSSuperStrings, this
is of little relevance.
It all helps us live our lives without getting stressed. Until a time
when "autorelease -- deallocates an object when you don't need it
anymore" just doesn't cut it any more,
it will do :)
The problem is that the description simply does not "cut it", and
failure to understand the basics of memory management does lead to
considerable stress for people.
Both of these statements:
release -- deallocates an object _right away_
autorelease -- deallocates an object when you don't need it anymore
(generally at the end of whatever method the autorelease is declared)
are fundamentally wrong:
release
-------
Consider:
NSString *fullName = [NSString alloc] initWithFormat:@"%@ %@",
firstname, lastName];
[myArray addObject:fullName];
[fullName release];
fullName is *not* deallocated _right away_. The array holds on to it.
autorelease
-----------
Simply because an object is autoreleased does *not* mean that it will
be deallocated "when you don't need it anymore" -- this broad statement
does not take account of any retains that might have been sent in the
interim (cf. also release above). Further, it is not "generally
[released] at the end of whatever method the autorelease is declared"
-- to see why this is (a) wrong and (b) confusing, consider a standard
convenience constructor:
+ (Person *) person {
return [[[self alloc] init] autorelease];
}
The misleading / incorrect statements in the original reply will lead
to confusion and stress for newcomers -- as indeed your subsequent
question suggests:
Of course, the next question (and one not made very clear by any of the
many documents I have read) is exactly -when- autoreleased items are
cleared.
Objects are "cleared" (deallocated) when their retain count drops to 0.
"Generally", that's as much as we need to, or -- in the absence of any
other context -- can, say (bearing in mind basic rules of memory
management).
In practical terms, however, it may be useful for a developer to be
aware of when autoreleased objects will be sent a release message, in
order that they may try to determine whether memory usage may become
excessive (e.g. if a large number of temporary objects is created and
not promptly disposed of).
More information is given in Apple's documentation:
<
http://developer.apple.com/techpubs/macosx/Cocoa/TasksAndConcepts/
ProgrammingTopics/MemoryMgmt/index.html#//apple_ref/doc/uid/10000011i>
->
<
http://developer.apple.com/techpubs/macosx/Cocoa/TasksAndConcepts/
ProgrammingTopics/MemoryMgmt/Concepts/AutoreleasePools.html>
"NSAutoreleasePools are automatically created and destroyed in
applications based on the Application Kit, so your code normally does
not have to worry about them. (***The Application Kit creates a pool at
the beginning of the event loop and releases it at the end.***)"
(My emphasis.)
So to answer your question; if you have not created any autorelease
pools of your own, any autoreleased objects will be sent a release
message at the end of the current event loop (one release message per
autorelease message they were sent).
There may, as hinted above, be some situations in which you want to
create your own autorelease pool:
(1) As per the documentation, "if you spawn a secondary thread, you
must create your own autorelease pool as soon as the thread begins
executing".
(2) If you create a large number of temporary autoreleased objects.
The important thing to realise about autorelease pools is that they're
"nested". An autoreleased object is "added" to the "most recently
created" autorelease pool. Consider the following, almost contrived
and almost deliberately confusing example:
- (NSDecimalNumber *)total {
NSEnumerator *itemEnumerator = [[self items] objectEnumerator];
Item *item;
NSDecimalNumber *total = [[NSDecimalNumber zero] retain];
while (item = [itemEnumerator nextObject]) {
NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
NSDecimalNumber *amount = [item amount];
if (amount) {
// ****
NSDecimalNumber *newTotal = [[total
decimalNumberByAdding:amount] retain];
[total release];
total = newTotal;
}
[myPool release];
}
[total autorelease];
return total;
}
The newTotal NSDecimalNumber created within the loop (at ****) is added
to the most-recently-created autorelease pool (myPool). Thus with the
somewhat more complex arrangement of retains and releases, we ensure
that no sub-totals remain in memory longer than necessary.
Contrast the more straightforward implementation:
- (NSDecimalNumber *)total {
NSEnumerator *itemEnumerator = [[self items] objectEnumerator];
Item *item;
NSDecimalNumber *total = [NSDecimalNumber zero];
while (item = [itemEnumerator nextObject]) {
NSDecimalNumber *amount = [item amount];
if (amount) {
total = [total decimalNumberByAdding:amount];
}
}
return total;
}
Here a potentially large number of temporary subtotals will exist -- by
default, assuming no other autorelease pools have been created by the
developer -- until the end of the current event loop.
Using lightweight objects like numbers may not be entirely convincing,
but it serves to make the example relatively comprehensible (and
NSNumber is a convenient example since the only available instance
methods return autoreleased objects). Consider the situation when
large numbers of other more memory-consuming objects might be created
(image manipulation, for instance); use of your own autorelease pools
may have a significant advantage in reducing the peak memory footprint
of your application. And the only way to ensure that you use these
properly, is to ensure that you properly understand memory management.
mmalc
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.