Previous 1 2 Next 16 Replies Latest reply: Sep 23, 2008 2:45 PM by Scott Squires1
applehund Level 1 Level 1 (5 points)

int main(int argc, char *argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;

}


This main autorelease pool that handles all my autoreleased objects in the main thread, does it only release its objects when my app is finished?

If that's the case, then can't my app crash if the user uses it for a long time since those autoreleased objects are only released when the app finally closes?

Thanks

Message was edited by: applehund

macbook, Mac OS X (10.5.4)
  • just.do.it Level 3 Level 3 (850 points)
    Hi,

    the release does not mean that your unreferenced objects will release. It means the Pool-object will be released.
    As far as i understood the objects will be released each time the runloop is entered.

    I forget to retain some objects in one of my apps some weeks ago and they were definitely release beause i got some realy strange efects.
  • applehund Level 1 Level 1 (5 points)
    I don't quite understand.

    Basically my question boils down to:

    "Do autoreleased objects still stay in memory until their autoReleasePool is released?"

    Because that would mean that if the user had my app open for a long time, it would eventually crash since I'm always allocating and autoreleasing objects and they wouldn't be released until the app closed.

    Thanks
  • orangekay Level 5 Level 5 (4,085 points)
    applehund wrote:

    Basically my question boils down to:

    "Do autoreleased objects still stay in memory until their autoReleasePool is released?"


    If they did don't you think that would be a pretty big problem for every Cocoa application ever written? Objects are deallocated on the next trip through the run loop after their reference count reaches 0. This is all extremely well documented.
  • applehund Level 1 Level 1 (5 points)
    I understand that it would be a big problem for all Cocoa applications and I know it's handled, but I want to understand it a bit more.

    {quote}You add an object to an autorelease pool so it will receive a release message—and thus might be deallocated—when the pool is destroyed.{quote}

    This is in the docs, so how do autoreleased objects get their reference count to 0 if they are only sent a release message when the pool is destroyed?

    Doesn't this mean that when the main() autoreleasepool is destroyed, only then do all the autoreleased objects get released?

    {quote}Objects are deallocated on the next trip through the run loop after their reference count reaches 0.{quote}

    I'd understand this more if I knew how their reference count got to 0 before the main() autorelease pool was released.

    Thanks
  • Xanthos Level 3 Level 3 (540 points)
    As the documentation states, objects created with a pool on the pool stack are only released when that pool is released. Following this logic leads to the conclusion that there are a number of objects that will only be reclaimed when the application exits. Remove the autorelease pool lines in main.m to see the objects leaked in the console window - there are only a handful of objects that are leaked and the leak messages stop shortly after the application starts. This is probably the point where the Cocoa runloop pool is put in place.

    I believe the pool in main.m is put in place to avoid the warnings that will ensue between the time the application starts up and the Cocoa runloop is put in place. Now at the beginning of that main runloop within Cocoa an autorelease pool is allocated - it is released and reallocated each time around the main run loop. This takes care of the objects autoreleased by an application in the general case.

    I have not seen the source Cocoa source code but this explanation makes the most sense to me given all the evidence.
  • applehund Level 1 Level 1 (5 points)
    I see, so there's an autorelease pool that I'm not seeing in the main runloop?

    That sounds pretty reasonable.

    Thanks
  • Xanthos Level 3 Level 3 (540 points)
    Yes, you do not see the main run loop. UIApplicationMain is the entry point into Cocoa that implements that for you.
  • orangekay Level 5 Level 5 (4,085 points)
    What evidence would this be?


    // Evidence.h

    #import <Cocoa/Cocoa.h>

    @interface Evidence : NSObject {

    }

    @end



    // Evidence.m

    #import "Evidence.h"

    @implementation Evidence

    - (void) dealloc
    {
    NSLog(@"Evidence go bye bye");

    [super dealloc];
    }

    @end



    // MyDocument.m

    #import "MyDocument.h"
    #import "Evidence.h"

    @implementation MyDocument

    - (id)init
    {
    self = [super init];
    if (self) {

    Evidence *debunker = [[[Evidence alloc] init] autorelease];

    }
    return self;
    }


    Output log:


    [Session started at 2008-09-22 12:57:11 -0700.]
    2008-09-22 12:57:12.327 Evidence[49785:10b] Evidence go bye bye

    The Debugger has exited with status 0.


    Note that the object was destroyed well before the application exited. Pools can be drained at any time.
  • Xanthos Level 3 Level 3 (540 points)
    Orangekay can you point me to the document that tells me that "Pools can be drained at any time"? From what I have read it only happens at very well defined points, namely when the pool is destroyed. Remember that in Cocoa Touch drain == release for pools.

    As to your snippet - I think you missed the point of the discussion. It is expected that once UIApplicationMain is called there is a Cocoa supported run loop in place that will clean up its own pools. I suspect you created the MyDocument object after the Cocoa run loop was set up in which case Cocoa is cleaning up after you as expected. Or perhaps you were running in a garbage collected environment in which case there is no need for autorelease pools.

    The claim is that the pool created outside the Cocoa run loop will not be cleaned up until it is released since the rules outlined in the documents on autorelease pools are followed. As further evidence try running the following as a Cocoa Touch application.


    #ifndef TARGETOSIPHONE
    #import <Cocoa/Cocoa.h>
    #endif

    @interface Evidence : NSObject
    {
    }
    @end

    @implementation Evidence
    - (id) init
    {
    if (self = [super init])
    {
    NSLog(@"Evidence lives");
    }
    return self;
    }
    - (void) dealloc
    {
    NSLog(@"Evidence has been autoreleased");
    [super dealloc];
    }
    @end


    int main(int argc, char *argv[])
    {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    Evidence *debunker = [[[Evidence alloc] init] autorelease];
    #if TARGETOSIPHONE
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    #else
    int retVal = NSApplicationMain(argc, (const char **) argv);
    #endif
    [pool release];
    return retVal;
    }
  • orangekay Level 5 Level 5 (4,085 points)
    Xanthos wrote:
    As to your snippet - I think you missed the point of the discussion. It is expected that once UIApplicationMain is called there is a Cocoa supported run loop in place that will clean up its own pools. I suspect you created the MyDocument object after the Cocoa run loop was set up in which case Cocoa is cleaning up after you as expected. Or perhaps you were running in a garbage collected environment in which case there is no need for autorelease pools.


    Yup; an actual Cocoa application has no such forced instantiation in main.m. Clearly whatever behavior you're seeing is something that was cooked up for the iPhone which I have no experience with whatsoever. Nevertheless, I would not expect to see autoreleased objects accumulate indefinitely under any circumstances that could be considered normal on either platform.
  • Scott Squires1 Level 3 Level 3 (910 points)
    By default a developer isn't required to create a pool.

    From the iPhone Programming Guide. p 72
    Objects released using the autorelease method stay in memory until you
    explicitly drain the autorelease pool or until the next time around your event
    loop.
    ...
    Whenever possible, avoid using the autorelease method when you
    can instead use the release method to reclaim the memory occupied by the
    object immediately. If you must create moderate numbers of autoreleased
    objects, create a local autorelease pool and drain it periodically to reclaim the
    memory for those objects before the next event loop.

    p. 87
    When an application starts running in iPhone OS, the operating system calls the standard entry point:
    the main function. The main function must always do three things:
    1. Create a top-level autorelease pool.
    2. Call the UIApplicationMain function.
    3. Release the autorelease pool after UIApplicationMain returns.

    My reading of this is the top level pool accumulates anything you don't assign to your own pools.
    It's not released until the app quits but it will drain on every event loop.
  • Xanthos Level 3 Level 3 (540 points)
    Scott Squires1 wrote:
    It's not released until the app quits but it will drain on every event loop.


    The second half of your sentence contradicts the first half. You should understand that drain == release. It does not seem plausible that Cocoa Touch is going to reach out and release the top level pool behind your back. You allocated it and you own it - that is the Cocoa model. Cocoa Touch creates its own pool each time through its event loop and at the bottom of the loop it drains (releases) its pool(s). Read the docs on threading and operations and you can see examples of this pattern.

    So this means that the objects that Cocoa Touch puts into that pool before it gets its run loop pool in place are held hostage for the duration of the application. From the look of them I'm guessing that these are things related to loading the main nib file but who knows.

    It is interesting to note that Cocoa does not require the top level pool in main.m like Cocoa Touch does.
  • Scott Squires1 Level 3 Level 3 (910 points)
    That's just it. It's the default template setup.

    From the iPhone Programming Guide. p 72
    Objects released using the autorelease method stay in memory until you
    explicitly drain the autorelease pool or until the next time around your event
    loop.

    Every time through the event loop the autorelease pool is drained. Not released. Automatically.
    Otherwise memory allocation would accumulate and there would be no need to retain any of the autorelease items. If they only were released when the app ended there would be no autorelease elements.

    If you add code to the template and use a convenience allocation that object will be released the next time through the event loop.

    Also remember you don't make your own event loop but it still happens.
  • Xanthos Level 3 Level 3 (540 points)
    Scott, you have missed important details in your research and made invalid assumptions. Before you post please make a better attempt to know the subject matter. Read the rest of the documentation, not just the programming guide. The programming guide can be thought of as a summary for those new to iPhone programming. If you want to understand this you will have to dig a little deeper.

    What you may learn is that *drain == release* on the iPhone. So yes every time through the event loop a pool is created and the one in place released. In other words alloc is called at the top of the loop and release / drain is called at the bottom. Work with threads and operations in Cocoa and you will learn to recognize this pattern. Learn what a run loop looks like.

    For your next post I suggest you run my sample code above and explain to us why the the debunker object allocated in main is never de-allocated, even though it is added to the auto release pool in main.m by virtue of autorelease being called there.

    Also, please read this thread more carefully. There is no need to remind us of what has already been stated.
Previous 1 2 Next