2

In the Apple documentation, it says:

The AppKit and UIKit frameworks process each event-loop iteration (such as a mouse down event or a tap) within an autorelease pool block. Therefore you typically do not have to create an autorelease pool block yourself, or even see the code that is used to create one.

Now, this should be obvious, but I'll ask for confirmation anyway.

If I'm developing for what would eventually be a background process (via Grand Central Dispatch), but for simplicity I first just put it in viewDidLoad of the very first loading view so that my view actually won't be shown on the screen until all that (say) 2 minutes of processing is done, then during this two minutes all that default autorelease pool is never freed because it has not gone through the event loop-iteration yet, right? It would be just plain insane to hear a no, but I'm stuck in this growing memory problem, so I'm going to ask for a confirmation and hope for a good news.

If so, I should put my own autorelease block(s). I would still need the autorelease blocks if the processing is done in a background process via GCD, right?

El Developer
  • 3,345
  • 1
  • 21
  • 40
huggie
  • 17,587
  • 27
  • 82
  • 139
  • I'm assuming you're not using ARC right? – 8vius Aug 31 '12 at 16:19
  • Under Xcode 3, at least, if you run your app in the emulator and you create an autoreleased object where there's no autorelease pool in the "stack", the emulator will print out a warning in the console along the lines of: "No autorelease pool defined -- just leaking object xxx." It can be a chore to narrow down where these originate from, but it's a very useful message to be sure you're not getting. – Hot Licks Aug 31 '12 at 17:23

2 Answers2

4

I'll try to give you a complete answer of both your questions.

Part one. First pay attention to long running operations in the main threads. If for example your operation takes two minutes, the main thread will be blocked until it has completed. From the user point of view, the app will not be responsive for two minutes. Anyway, yes in the application delegate there is a pool where autoreleased objects are inserted. When the loop ends, the objects inside the pool are released since the pool is drained automatically. If you have memory problem you could take a look at Use Local Autorelease Pool Blocks to Reduce Peak Memory Footprint. As written in doc you should wrap an operation in a autorelease block. At the end of the block, the temporary objects are released, which typically results in their deallocation thereby reducing the program’s memory footprint.

About the GCD question I would say no. You don't have to create an autorelease pool when you deal with GCD. Usually, as also written in Do you need to create an NSAutoreleasePool within a block in GCD?, GCD manages an autorelease pool per queue automatically. So, if you have few objects you don't have to worry about it but if you create a lot of them, yes, create an autorelease pool. The latter allows you to reduce memory footprint as well.

So for this entire two minutes where the app will not be responsive, it is when the loop has not ended, and the pool is not drained during these two minutes, right?

The app is not responsive since the main thread (through the run loop) executes tasks in a sequential order. If you block the run loop the app freezes until the long running operation is finished (I think the app is killed by iOS if you exceed a specific period of time). To avoid this, you could perform (as you wrote) the long running operation in a different thread.

The goal of using thread is to make the application highly responsive but it could lead to various problem like inconsistent data (race condition) or deadlocks.

For further info I really suggest to read The pogo stick of NSRunLoop, Understanding NSRunLoop and NSDefaultRunLoopMode vs NSRunLoopCommonModes.

Community
  • 1
  • 1
Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
  • I need a clarification of your explanation. So for this entire two minutes where the app will not be responsive, it is when the loop has not ended, and the pool is not drained during these two minutes, right? – huggie Sep 01 '12 at 02:15
  • @huggie I expanded my answer. Hope it helps. – Lorenzo B Sep 01 '12 at 11:35
  • Great! I appreciate your help! I put more autorelease blocks and now my program walks through the entire process without puking. Now instruments report the live RAM usage was down to blow 2MB during my measurements and OS X's activity monitor shows RAM usage around 70 MB, whereas previously that would be taking a whopping 1GB of RAM. – huggie Sep 01 '12 at 11:52
0

You don't need to create your own autorelease block in order to manage the memory of autoreleased objects; there is a pool, it is automatically managed, and the autoreleased objects will eventually be released.

The only question, therefore, is the magic word "eventually." During your processing, does your app use too much memory (e.g., so much memory that the system will kill it) because of autoreleased objects that have not yet been released? Remember, they will be released; the question is whether the situation is so bad that you need to release them now, without waiting for the draining of the autorelease pool that certainly will happen without any action on your part.

Only Instruments can tell you, so don't guess and don't optimize prematurely; look to see what Instruments reveals. If the situation is that bad, then sure, find the loop that is generating all those autoreleased objects and put an autorelease block inside it, so that the pool is drained each time through the loop. Otherwise, there is really no need. (On the other hand, under ARC an autorelease block adds very little overhead, so it probably won't do much harm to optimize prematurely either.)

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • The cost of creating/managing an autorelease pool is minimal, so there's no real danger in being a little "excessive" in their use, provided correctness is maintained (ie, you don't autorelease too soon). In particular, where there is a relatively long-running loop that will be creating lots of local objects, it may be wise to add an autorelease range, without first doing the instrumentation thing. – Hot Licks Aug 31 '12 at 17:18
  • Well the fact is when running in my simulator, it runs to the point it can no longer alloc! So yeah it's using too much memory. I am thinking that I probably need to change all that stringWithFormat calls to initWithFormat, for example. Or I need my own autorelease block. – huggie Sep 01 '12 at 02:17
  • @huggie -- initWithFormat will do no good (in fact, will be worse) unless you have the corresponding `release` somewhere. – Hot Licks Sep 01 '12 at 13:47
  • @HotLicks This project has ARC so I won't be writing `release`. But I only see it as the same if I really do need it and keeps it around. How can it be worse? – huggie Sep 01 '12 at 15:35