0

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
      }
   }

}
aryaxt
  • 76,198
  • 92
  • 293
  • 442
  • 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](http://stackoverflow.com/questions/5012886/knowing-available-ram-on-an-ios-device). – Till Aug 20 '12 at 19:46
  • @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 Aug 21 '12 at 00:53

3 Answers3

4

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.

bbum
  • 162,346
  • 23
  • 271
  • 359
0

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.

Nathan Day
  • 5,981
  • 2
  • 24
  • 40
-1

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.

Raphael Ayres
  • 864
  • 6
  • 16
  • I wish it was manual retain count, but no it's ARC. And the code is already running on a different thread. – aryaxt Aug 20 '12 at 19:58
  • 1
    What do you mean by this "@autorelease pool is the part of the heap responsible for statically allocated objects?" – Jody Hagins Aug 20 '12 at 20:20
  • @JodyHagins that phrase doesn't make sense; the autorelease pool is responsible for releasing all objects in the pool when drained, no more, no less. – bbum Aug 20 '12 at 20:22
  • You might have misunderstood my words @JodyHagins. The autorelease pool releases objects initialized with autorelease or like this [NSString stringWithstring:], in the scope of autoreleasepool, not all objects. In ARC case, when you alloc/init an object, it inserts code on compilation time to release the object. The only objects released by autoreleasepool are those which you initialize without calling alloc. It's actually not statically allocated, i mispoke here, I was just trying to differentiate things. And they ARE initialized in the heap, like all obj-c objects. Thanks for the -1, though. – Raphael Ayres Aug 20 '12 at 21:11
  • "The only objects released by autoreleasepool are those which you initialize without calling alloc". I would appreciate any source confirming this statement. I find it hard to believe because ARC doesn't allow autorelease and therefore you can't take advantage of @autoreleasepool (in the middle of a scope) based on your statement. – aryaxt Aug 20 '12 at 21:32
  • @RaphaelAyres I think your understanding of the auto release pool is slightly flawed. Also, all objects which conform to NSObject should be created by calling alloc (followed by some form of initialization -- the "Two-Stage Creation" pattern), so I don't understand that part either. BTW, you owe your thanks for the -1 to someone else though... your statement didn't make sense to me, but I thought maybe you were just using terminology foreign to me. – Jody Hagins Aug 21 '12 at 00:50