Skip navigation.
 
mlRe: Leaking Memory
FROM : mmalcolm crawford
DATE : Fri Jan 24 22:58:21 2003

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_removed>
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.

Related mailsAuthorDate
mlLeaking Memory Nebagakid Jan 20, 23:51
mlRe: Leaking Memory Shawn Erickson Jan 21, 00:42
mlRe: Leaking Memory John C. Randolph Jan 21, 01:09
mlRe: Leaking Memory David Cairns Jan 21, 01:19
mlRe: Leaking Memory Shawn Erickson Jan 21, 01:51
mlRe: Leaking Memory Denis Stanton Jan 21, 02:34
mlRe: Leaking Memory Mark Levin Jan 21, 03:17
mlRe: Leaking Memory Mike Shields Jan 21, 04:33
mlRe: Leaking Memory David Cairns Jan 21, 04:50
mlRe: Leaking Memory Angela Brett Jan 21, 07:15
mlLeaking Memory Robert Goldsmith Jan 21, 12:12
mlRe: Leaking Memory mmalcolm crawford Jan 23, 02:32
mlRe: Leaking Memory Robert Goldsmith Jan 24, 03:33
mlRe: Leaking Memory mmalcolm crawford Jan 24, 22:58
mlRe: Leaking Memory Robert Goldsmith Jan 25, 03:07
mlRe: Leaking Memory mmalcolm crawford Jan 25, 06:36
mlRe: Leaking Memory Greg Titus Jan 25, 08:04