Question

I have a requirement to create some NSDecimalNumber objects objects as part of my application (as I require the precision of calculation they offer) but I note that in calculations they return NSDecimalNumber objects which are, presumably, autoreleased.

My question is really whether this is potentially problematic in an iPhone application where I may carry out lots of calculations.

The question is not just relating to NSDecimalNumber specifically but to the sometimes unavoidable creation of autoreleased objects in the course of developing an iPhone application.

Any detailed answers on this point would be gratefully received.

Was it helpful?

Solution

Yes, creating lots of autoreleased instances on the iPhone can create memory problems, particularly in a tight loop, which is why I tend to avoid them when I can. You can create your own autorelease pools to manage this, but they also add some performance overhead and additional code that you have to keep track of.

It is for this reason that when I do high-precision calculations, I tend to use the NSDecimal C struct instead of NSDecimalNumbers. In fact, I performed some benchmarks on this and found a significant performance increase when going with the C struct (copied from my answer here):

NSDecimal

Additions per second: 3355476.75
Subtractions per second: 3866671.27
Multiplications per second: 3458770.51
Divisions per second: 276242.32

NSDecimalNumber

Additions per second: 676901.32
Subtractions per second: 671474.6
Multiplications per second: 720310.63
Divisions per second: 190249.33

As you can see, there is almost a fivefold increase in calculation speed between the NSDecimal paths and NSDecimalNumber ones. The biggest difference between the NSDecimal and NSDecimalNumber calculations was the memory allocation of the NSDecimalNumber instances. Therefore, you should avoid allocating temporary autoreleased instances wherever you can.

OTHER TIPS

Remember, you can create your own NSAutoreleasePool objects.

For example:

for (int i = 0; i < 1000; ++i) {
  NSAutoreleasePool * p = [[NSAutoreleasePool alloc] init];
  for (int j = 0; j < 1000; ++j) {
    NSString * s = [NSString stringWithFormat:@"%d,%d", i, j];
    NSLog(@"%@", s);
  }
  [p release];
}

If you do that, you'll never have more than 1000 of those strings in memory at a time.

If you are worried about handling too many autoreleased objects you can create your own autorelease pool (see memory management):

for (count = 0; count < limit; count++)
{
    NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
    NSString *fileContents;
    NSString *fileName;

    fileName = [args objectAtIndex:count];
    fileContents = [[[NSString alloc] initWithContentsOfFile:fileName] autorelease];
    // this is equivalent to using stringWithContentsOfFile:

    /* Process the file, creating and autoreleasing more objects. */

    [loopPool release];
}

Every object that is given a chunk of memory will have to relinquish it. The question is when.

I try to alloc/init/release when I can, so that objects only hang around as long as they are needed.

If I use autorelease I have less control over when the object is released. If the application tries to access a released object then it can crash. So tighter memory management is a good thing, I think.

So long as you retain autoreleased objects returned from a method, you should be okay. (Unless you're asking about something else, in which case I apologize in advance.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top