views:

64

answers:

3

Hi,

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.

+1  A: 

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];
}
kubi
+1  A: 

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.

David Gelhar
+5  A: 

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.

James Huddleston
Am I correct in my understanding that I can't manually release objects created by decimalNumberBySubtracting? Is that going to result in a problem when the objects it creates get autoreleased?
John Carter
Yes. The only way to "manually release" objects that have already been autoreleased is to use an autorelease pool as the example code shows.
David Gelhar
You are correct. If you don't own the object, you shouldn't release it. The autorelease pool will release the object, so if you release it, it will end up getting released twice.
James Huddleston
Thanks for the recommendation, the Apple Dev guide to Memory Management is exactly what I needed. Things were getting a bit oversimplified/glossed over in other things I've read.
John Carter