views:

14890

answers:

6

As I understand it, anything created with an alloc, new, or copy needs to be manually released. For example:

int main(void) {
    NSString *string;
    string = [[NSString alloc] init];
    /* use the string */
    [string release];
}

My question, though, is wouldn't this be just as valid?:

int main(void) {
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
    [pool drain];
}
+10  A: 

Yes, you're second code snippit is perfectly valid.

Every time -autorelease is sent to an object, it is added to the outer-most autorelease pool. When the pool is drained, it simply sends -release to all the objects in the pool.

Autorelease pools are simply a convenience that allows you to defer sending -release until "later". That "later" can happen in several places, but the most common in Cocoa GUI apps is at the end of the current run loop cycle.

kperryua
where's the end of the current run loop cycle, if I don't have an loop?
Thanks
Shouldn't "outer-most" be "inner-most"?
Mike Weller
A: 

Yes and no. You would end up releasing the string memory but leaking the NSAutoReleasePool object into memory by using drain instead of release if you ran this under a garbage collected (not memory managed) environment.

drain

In a garbage collected environment, triggers garbage collection if memory allocated since last collection is greater than the current threshold; otherwise behaves as release.

Otherwise, it's similar, yes. I should point out that your statement "anything called with new, alloc or init" should not include "init", because "init" doesn't allocate memory, it only sets up the object (constructor fashion). If you received an alloc'd object and your function only called init as such, you would not release it:

- (void)func:(NSObject*)allocd_but_not_init
{
    [allocd_but_not_init init];
}

That does not consume any more memory than it you already started with (assuming init doesn't instantiate objects, but you're not responsible for those anyway).

Loren Segal
I don't feel comfortable leaving this answer as accepted when your information about drain isn't quite right. Seehttp://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html#//apple_ref/doc/uid/20000051-SW5Update and I will re-accept.
jsumners
What is inaccurate about the reply? In a garbage collected environment (as stated), drain does not delete the AutoReleasePool, so you *will* leak memory unless you used release. The quote I listed was straight from the horse's mouth, the docs on drain.
Loren Segal
Loren: Under GC, -[NSAutoreleasePool drain] will trigger a collection. -retain, -release, and -autorelease are all ignored by the collector; that's why -drain is used on autorelease pools under GC.
Chris Hanson
In the documentation for 'drain':In a managed memory environment, this behaves the same as calling release.Thus you will *not* leak memory if you use 'drain' instead of release.
mmalc
`-[NSAutoreleasePool release]` in a garbage-collected environment is a no-op. `-[NSAutoreleasePool drain]` works in both reference-counted and garbage-collected environments.
Jonathan Sterling
+2  A: 

No, you're wrong. The documentation states clearly that under non-GC, -drain is equivalent to -release, meaning the NSAutoreleasePool will not be leaked.

kperryua
I wondered why Xcode would generate code with -drain if that were the case. I used -drain because I thought it was equivalent to -release based on the code generated by Xcode.
jsumners
It is fundamentally impossible to 'leak' a `NSAutoreleasePool`: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html#//apple_ref/doc/uid/20000047-997594
johne
+9  A: 

NSAutoreleasePool: drain vs. release

Since the function of drain and release seem to be causing confusion, it may be worth clarifying here (although this is covered in the documentation...).

Strictly speaking, from the big picture perspective drain is not equivalent to release:

In a reference-counted environment, drain does perform the same operations as release, so the two are in that sense equivalent. To emphasise, this means you do not leak a pool if you use drain rather than release.

In a garbage-collected environment, release is a no-op. Thus it has no effect. drain, on the other hand, contains a hint to the collector that it should "collect if needed". Thus in a garbage-collected environment, using drain helps the system balance collection sweeps.

mmalc
It is fundamentally impossible to 'leak' a `NSAutoreleasePool`. This is because pools operate like a stack. Instantiating a pool pushes that pool on to the top of that threads autorelease pool stack. `-release` causes that pool to pop from the stack **AND** any pools that were pushed on top of it, but for whatever reason were not popped.
johne
In what way is this relevant to what I wrote?
mmalc
A: 

yeah your code is perfect, if you'd be using garbage collecting it would be enough to just set the string to nil when you are done with it. Garbage collecting is not good for the performance of your app so I would not recommend using it :P

Antwan van Houdt
A: 

I found this link gave the best explanation on when and how to use NSAutoReleasePool: http://www.cocoadev.com/index.pl?AutoReleasePool

Wayne Lo