0
votes

So the app was crashing with no stack trace or any exceptions, and I could replicate this crash every time. My first thought was that it has to be a double release, after running zombies for 10 minutes, I was not able to get the app to crash, not even once.

After looking at Allocations I noticed a huge jump in the size of allocated objects when the method gets called. So I ended up having an @autoreleasePool inside the for loop. this autorelease pool fixed the crash; but how can I confirm that this really was an out of memory issue? (didRecieveMemoryWarning did not get called at any time before the crash)

Why does autoreleasePool fix the problem?

Why doesn't didRecieveMemoryWarning get called? Is it because application runs out of memory before we get to the end of the current runloop?

- (void)doSomething
{

   for (Item *item in self.items)
   {
      @autoreleasepool
      {
         // A bunch of initializations here that take a lot of memory
      }
   }

}
3
Something I tend to use now and then to get a qualitative answer on memory allocations (additionally to using instruments) can be found within this answer.Till
@autoreleasepool is a useful tool, and should be used almost anytime you are allocating temporary objects in a loop. With the performance improvements, there's really no good reason NOT to use it -- until Instruments tells you otherwise.Jody Hagins

3 Answers

4
votes

Use Instruments to monitor allocations and see if it rises without the autorelease pool.

If the crash happens particularly fast or you are blocking the queue upon which the memory notification happens, you won't see the notification.

Autorelease is fixing the issue most likely because there are a ton of autoreleased objects created as a part of your initializations. The pool won't be drained until the loop is exited.

0
votes

didRecieveMemoryWarning is not called asynchronously, your main thread has to return to the NSRunLoop to get the next event which could be a call to didRecieveMemoryWarning. Besides even if it was you would not be able to clean up all of the objects on the autorelease pool, so its doubtful you could do much if the issue was lots of autorelease pool stuff.

-1
votes

Is this running on the same thread of UIApplicationMain? Does the for scope allocs lots of objects with alloc/init? Is ARC enabled?

@autorelease pool is the part of the heap responsible for objects allocated without explicit call to init, like /[NSString stringWithFormat:"%@",format]/ or returned with autorelease like /[[[NSObject alloc] init] autorelease]/.

The problem must have disappeared because each time you reach the end of the loop, it performs a [pool drain], releasing any statically allocated objects in that scope. I would sugest that you create another thread to perform this allocations and pause the main thread in between (maybe with UIAlertView?). When you create an autoreleasepool inside another autoreleasepool, the second might get stuck into the first, that will only be released in the end of the application. Hope it helps.