Can we have multiple NSAutoReleasePools? Why would this be necessary? - objective-c

NSAutoreleasePool .. should there be only one? Why would you want to have more then one? Would you ever want to have more than one pool as part of a single class?
If you have multiple pools, which one will contain object that was asked for be [autorelease]d? Is there a way to find out what objects are waiting to be auto-released as part of a pool?
Sorry for 20 questions, please help me understand this better

NSAutoreleasePool .. should there be
only one?
No, not necessarily. You may create as many autorelease pools as you want/need.
Why would you want to have more then
one? Would you ever want to have more
than one pool as part of a single
class?
The idea is to keep your memory "high water mark" as low as possible. Using autorelease is a bit of a cheat to defer releasing your object until "later". Sometimes you know when "later" is -- and in these cases, it's probably smart to make your own autorelease pool.
What do I mean by all this? Well, imagine you had the following loop:
for (...)
{
// 1 MB of objects are added to the autorelease pool by some code...
}
1 MB is a lot! If that code looped 20 times, you'd have 20MB of objects waiting to get released. Even worse, if it ran for an indefinite or indeterminate number of times your application may very well crash. If you know that code is self-contained you can force anything that gets put into an autorelease pool within that block to get released by creating your own autorelease pool manually, like so:
for (...)
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// 1 MB of objects are added to the autorelease pool by some code...
[pool drain];
}
Now your "high water mark" is only 1MB instead of 20MB (or more!).
If you have multiple pools, which one
will contain object that was asked for
be [autorelease]d?
The most recent one.
Imagine having a global stack. When you init a new AutoreleasePool, it adds itself to this global stack of autorelease pools. When you call [xxx autorelease] on an object, the autorelease method peeks at the autorelease pool on the top of this stack and adds itself to that autorelease pool's list of objects. When you call [pool drain], that pool loops through all of the references that have been added to it and it calls [xxx release] on all of them.
As BJ Homer points out, the stack in the paragraph above isn't actually truly global - there is actually one stack per thread. But I couldn't figure out how to rewrite the above paragraph and keep it easily understandable by using terms like "thread-local"... so... this addendum will have to suffice : )

Related

Usage of autorelease pool in objectAtindex swizzling for NSMutableArray

- (nullable id)myObjectAtIndex:(NSUInteger)index{
#autoreleasepool {
id value = nil;
if (index < self.count)
{
value = [self myObjectAtIndex:index];
}
return value;
}
}
I have no idea about the purpose of using autoreleasepool here. Can someone give me a hand?
Unless I'm missing the obvious, which is always possible, we can only guess:
There is a stack of autorelease pools, the top of the stack being the one in use. When the #autoreleasepool { ... } construct is entered a new pool is created and pushed on the stack, on exit from the construct the pool is drained and popped off the stack.
The reason to create local pools is given in the NSAutoReleasePool docs (emphasis added):
The Application Kit creates an autorelease pool on the main thread at the beginning of every cycle of the event loop, and drains it at the end, thereby releasing any autoreleased objects generated while processing an event. If you use the Application Kit, you therefore typically don’t have to create your own pools. If your application creates a lot of temporary autoreleased objects within the event loop, however, it may be beneficial to create “local” autorelease pools to help to minimize the peak memory footprint.
So what is the purpose in the code you are looking at? Some guesses:
Either the original author knows/believes that the called methods count and objectAtIndex (post the swizzle) add a significant amount of objects to the autorelease pool and wishes to clean these up; or
The original author was/is planning to add future code to myObjectAtIndex which will add a significant amount of objects to the autorelease pool and wishes to clean these up; or
Wishes to be able to call objectAtIndex and ensure there is no impact on the memory used for live objects (e.g. maybe they were measuring memory use by something else); or
Who knows, accept the original author (hopefully!)
HTH
There is no scientific reason.
The whole code is an example of "this app crashes and I do not know why" panic code:
Obviously the author had a problem with guaranteeing correct indexes, what would be the correct approach. Therefore he wrote a special method to "repair" it. The naming ("my") shows, that he thought: I can do it better (instead of insuring correct indexes).
Moreover, adding an ARP to a piece of code, that obviously does not create an bigger amount of objects, is a sure sign for the fact, that he couldn't oversee his code anymore.
Move the whole code to /dev/null.

Objective-C Memory Management: Am I understanding this?

I've finally decided to stop beating around the bush and teach myself some Objective-C. It's all making sense, except when I get to the memory management and this idea of the "autorelease pool".
From my understanding, if I specifically create an object using init,new, alloc or tell it to retain, then it is my job to deallocate the memory. However, an autorelease pool will automatically free up any objects associated with the innermost autorelease pool?
For example, say I do this:
TestOBJ* foo = [[[TestOBJ alloc] innit] autorelease];
Then it will be released at the end of the first #autoreleasepool block, or whenever the first [autoreleasepool drain] is called?
Also; just because an object is created within an autoreleasepool block doesn't mean it is automatically labeled as autorelease, correct?
Correct for both points.
Objects only get added to autorelease pools if you call -autorelease on them. By convention all methods not starting with alloc, new, copy or mutableCopy return objects that they have themselves added to the autorelease pool, so you don't have to do it yourself.
See http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html for details.
You pretty much answered all your questions yourself correctly.

Memory considerations for BFS in Objective-C

I've written a puzzle solver in Objective-C. It uses a breadth first search to explore the states reachable from the initial puzzle state. The search is terminated when the first winning state is encountered. The only optimization is a look-up table that helps prevent re-exploring from a state already seen.
The algorithm seems to work correctly. However profiling shows it's using a lot of memory and I'd like to understand why. I think my gap in understanding is related to the Objective-C run loop and the autorelease pool.
Does the following (simplified) code ever allow the run loop to complete an iteration and drain the autorelease pool?
- (void) search {
while (![myQueue empty]) {
State *state = [myQueue pop];
for (State *s in [state allReachableStates]) {
[myQueue push:s];
}
}
}
Profiling shows lots of memory used for NSArrays. This makes sense as allReachableStates does create a fair number of arrays. Since they're all autoreleased it seems possible that the above code is preventing the autorelease pool from draining.
Note all code is run on the main thread and I'm not using ARC.
Edit: So the fix was wrapping the for loop in an #autoreleasepool.
You're right that the autorelease pool associated with this turn of the runloop won't be drained within this method. It won't be drained until some time after this method returns.
You can wrap the while block in an #autoreleasepool yourself (one for each state)
It's better not to use a lot of autorelease in a for loop. You can check this Understanding Objective-C autorelease memory management

scope of autorelease pool

Does NSAutoreleasePool also covers variables in all the called methods?
If that's the only place where -isNotExpired is called, the auto release pool you've set up will contain objects autoreleased in -isNotExpired (including startDate).
Note that in a normal Cocoa application, NSApplicationMain() called in main() in main.m will create an autorelease pool for you, so this code wouldn't leak anyway. You generally only create your own autorelease pool in cases where you'll be generating lots of temporary objects with a short useful life (in a loop for instance) and want to keep your high water memory usage down.

Reducing the memory footprint of a function with a lot of autoreleased variables?

I'm still wrapping my head around some of the nuances of memory management in objective-C, and came up with the following case I'm unsure about:
+ (NSDecimalNumber*)factorial: (NSDecimalNumber *)l {
NSDecimalNumber *index = l;
NSDecimalNumber *running = [NSDecimalNumber one];
for (; [index intValue] > 1; index = [index decimalNumberBySubtracting:[NSDecimalNumber one]]) {
running = [running decimalNumberByMultiplyingBy: index];
}
return running;
}
Here decimalNumberByMultiplyingBy and decimalNumberBySubtracting will be creating a lot of NSDecimalNumbers, which will get autoreleased eventually as I understand it, but I worry until that time the containing program will be hanging unto an awful lot of memory.
Should I be introducing an autorelease pool somewhere? (If so where?) Is that going to have a noticeable effect on performance (when compared to the side effect of so much memory in use)?
Is autoreleasing the right mechanism to use here? Should I look at breaking the loop apart and manually releasing memory as I'm done with it?
It's likely a n00b question, but I'm trying to get a flavour for what the best practice(s) is/are in this situation.
It's good practice to avoid creating a bunch of large autoreleased objects within a single pass of the run loop. You already seem aware of the solutions. You can use non-autoreleased objects and release them when you're done with them. You can also create an autorelease pool for sections of your code that create a large number of autoreleased objects. When an object is autoreleased, it gets released when the enclosing autorelease pool is released/drained. Using an autorelease pool would look like this:
NSAutoReleasePool *subPool = [[NSAutoreleasePool alloc] init];
// Code that generates a bunch of autoreleased objects.
[subPool release];
But, before you do any optimization, run some benchmarks and see if you actually need to optimize. My guess is that the method you've shown won't cause any problems. However, let's say you're trying to apply your method to a set of a million random integers within a single loop. In that case, you might benefit from using an autorelease pool.
Check out Apple's Memory Management Programming Guide for Cocoa for more details.
You could set up an autorelease pool within the loop, but why bother?
You are not going to be able to accumulate that many objects in this loop, because you're computing factorials, and the largest exponent an NSDecimalNumber can have is 127.
You'll get an overflow error before you even get to 100 iterations through the loop.
Note that the main autorelease pool gets emptied every time the application makes a trip through the main run loop, so the autoreleased values are not going to hang around very long.
Best way to determine the answer is to write it a few different ways and test. I don't think this is going to be a problem, though, NSDecimalNumbers are going to max out around ~100!, and 100 NSDecimalNumber objects probably won't make a bit of difference.
Answer to your other questions: In situations where it will matter you can manually release your objects. You can also create an autorelease pool inside that loop. Autorelease is super fast.
while(/*condition*/) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// code goes here
[pool drain];
}