Performance of factory methods in Objective-C - objective-c

Is there any difference performance-wise in the following 2 snippets of code?
NSString* str = [[NSString alloc] initWithFormat:#"%i", 10];
// Do something with |str|.
[str release];
NSAutorelasePool* pool = [[NSAutreleasePool alloc] init];
NSString* str = [NSString stringWithFormat:#"%i", 10];
// Do something with |str|.
[pool drain];
I see people trying to suggest using factory methods whenever possible.
Isn't it better to release objects as soon as possible rather than when a pool is drained.
I would see the first type being very efficient in certain cases such as in tight-loops.

I see people trying to suggest using
factory methods possible.
I'd guess that's because it's basically the same thing, but you don't have to remember to release the object. Some might say that using the convenience method is a little more readable, too, especially since you don't have to end every method with a sequence of -release messages.
Isn't it better to release objects as
soon as possible rather than when a
pool is drained.
You can make that case in some situations, such as inside a loop. That's often not an important consideration, though... many methods don't loop at all and only create a handful of objects.
I would see the first type being very
efficient in certain cases such as in
tight-loops.
Sure. So you should know when it is and when it isn't appropriate to autorelease objects, and you should write your code accordingly. But it doesn't follow that you should always try to avoid autoreleasing objects any more than it makes sense to always try to use convenience methods.
BTW, if you're writing loops that iterate many times, you should consider creating an autorelease pool. Chances are, you'll be using other methods inside your loop, and those methods might create autoreleased objects. Using your own pool and draining it periodically prevents those objects from piling up. If you do that, though, it takes a great deal of wind out of the the idea that you shouldn't use autoreleased objects in your loop.

Yes it is. First one is better memory management, worth it if you are doing it, like you said, in a loop to avoid allocating a lot before the next pool drain.

Related

How to properly initialize objects in objective c with ARC

For many classes there are initXXX methods and typeXXX methods, for example:
NSNumber *n1 = [[NSNumber alloc] initWithInt:1];
NSNumber *n2 = [NSNumber numberWithInt:1];
I've read about manual memory management and I think that I understand how those lines are different with manual memory management (second is just shortcut for autoreleased object).
But with ARC I don't understand which API I should use? Should I use only alloc-init pattern because ARC is smart enough to make value autoreleased if necessary and avoid autorelease overhead when value is only used locally? Or ARC can optimize out autorelease and corresponding overhead even when I use something like numberWithInt?
I would like to use second variant when available, because it's shorter and easier to read. But I don't want to introduce performance overhead just for this reason.
Or ARC can optimize out autorelease and corresponding overhead even when I use something like numberWithInt?
It can, even with these convenience factory (so are they called) methods. Here all is explained well.
So you can use either one.

Under ARC, is it still advisable to create an #autoreleasepool for loops?

Let's say that I have a loop that returns a bunch of autoreleased NSData objects...
NSData* bigData = ...
while(some condition) {
NSData* smallData = [bigData subdataWithRange:...];
//process smallData
}
Under ARC, should I still wrap an #autoreleasepool around the while condition?
NSData* bigData = ...
#autoreleasepool {
while(some condition) {
NSData* smallData = [bigData subdataWithRange:...];
//process smallData
}
}
The reason why I'm asking is I see the living allocation count in instruments going through the roof for my NSData objects that invoke a dataWith... method as opposed to an initWith... method. When I use initWith..., the living allocation count is much, much less.
Is it better to prefer the initWith... methods whenever possible?
Yes you should still use autorelease pools when using convenience methods in a tight loop. All the old memory management rules still apply under ARC, the compiler is merely injecting RRs for you. Checkout the great post by the awesome Mike Ash!
Link
I think your issue is that the autorelease pool is supposed to go inside the loop. With the loop inside the autorelease block rather than vice-versa, the accumulated objects won't be released until after the loop finishes.
Under ARC, should I still wrap an #autoreleasepool around the while condition?
Yes. Autorelease Pools are still in place, and grow and pop as before. The compiler just adds and coalesces the necessary retains and releases operations when ARC is enabled (echoing Logan), based on the methods that are visible to the TU and default naming conventions.
Execution in ARC is nearly identical the manual reference counting: Autorelease pool stacks still exist. One difference is that the compiler may order the reference counting operations slightly different from the way you wrote it (not in an incorrect way), and may omit unnecessary retain cycles.
Is it better to prefer the initWith... methods whenever possible?
WRT minimizing heap growth compared to the autoreleased counterparts: Yes. That's always been the case. It's especially important on iOS devices, where memory is quite limited.
The exception to this is when the object may avoid an allocation. Example:
NSString * copy = [NSString stringWithString:arg];
in this case, copy may be [[arg retain] autorelease]. Note that in this case, copy is still autoreleased, but you should not usually go to great lengths to test the presence of such optimizations. Note: It's also better to use copy = [arg copy]...[arg release] here.
The other bonus is that your ref count imbalances are often caught earlier when the object is never autoreleased, and closer to the call site (rather than when the Autorelease Pool is finally popped).
Performance with large autorelease pools is actually much worse than most people would suppose. If you can avoid depending on them heavily (e.g. using alloc+init...+release), you can make your program noticeably faster. Explicitly creating autorelease pools is cheap, and can help minimize this problem. When allocations are large and/or numerous, avoid using autorelease on them where possible, and do wrap these sections in explicit autorelease pools.

Why is release often called shortly after a local var is used instead of just autoreleasing

I often see something like the following:
UIBarButtonItem *anotherButton = [[UIBarButtonItem alloc] initWithTitle:#"Show" style:UIBarButtonItemStylePlain target:self action:#selector(refreshPropertyList:)];
self.navigationItem.rightBarButtonItem = anotherButton;
[anotherButton release];
specifically where a local var, in this case 'anotherButton' is used and then later released. Is this exactly the same as autoreleasing it when it is alloc'ed and then making sure it is used before the method ends? i.e.:
UIBarButtonItem *anotherButton = [[[UIBarButtonItem alloc] initWithTitle:#"Show" style:UIBarButtonItemStylePlain target:self action:#selector(refreshPropertyList:)] autorelease];
self.navigationItem.rightBarButtonItem = anotherButton;
I ask because I see it done the first way a huge amount of the time, but it feels less error prone (for me) to just autorelease it outright. Is it just a matter of personal style or are there differences to these two approaches apart from one methodically releasing the object after all is done with it, and the other taking care to claim it to be released at the outset so one doesn't accidentally forget to, both having merits.
From Allocate Memory Wisely in Tuning for Performance and Responsiveness Table 7-2 Tips for allocating memory:
Tip
Reduce your use of autoreleased
objects.
Actions to take
Objects released using the autorelease
method stay in memory until you
explicitly drain the current
autorelease pool or until the next
time around your event loop. Whenever
possible, avoid using the autorelease
method when you can instead use the
release method to reclaim the memory
occupied by the object immediately. If
you must create moderate numbers of
autoreleased objects, create a local
autorelease pool and drain it
periodically to reclaim the memory for
those objects before the next event
loop.
When you autorelease something, you add it to a group of objects which will be released at some point in the future. This means that those objects still exist. Since iOS provides a limited amount of memory, it is suggested that you use release over autorelease whenever possible. You don't want your program to crash from low memory because you have a lot of autoreleased objects.
Excellent question. By autoreleasing, you are delaying the automatic release of objects. This is all fine and dandy and expected behavior when you need to return something from a method, but keeping that object in memory longer than is necessary can be impactful to your app.
By releasing it when you are done, you are freeing the resource at that moment and the memory could be used by another object at runtime. In Cocos2D it is standard practice to autorelease nearly everything and things seem to work OK, but it still rubs me the wrong way and I would not do that in general practice.
They accomplish the same thing. Some folks think you should avoid the use of autorelease whenever possible, so strongly prefer the release as soon as you can option. This was discussed here just yesterday.
In the code you cite, the difference between the two really is minimal. It's unlikely that anotherButton will be deallocated even after it's released because the assignment to self.navigationItem.rightBarButtonItem probably causes anotherButton to be retained.
The best argument for calling release as soon as possible, IMO and in this situation, is that by releasing anotherButton you're explicitly documenting the fact that you're done using it. Also, the static analyzer will ding you if you use anotherButton after the release. These two facts can help you avoid errors, and just make your code easier to understand.
The argument in favor of autorelease in a situation like this is that it might be marginally easier to read. I think there's a reason that Apple gives us all those convenience methods like +stringWithFormat: -- they let you create and use the string you want with one method rather than three.

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

Memory Management Autorelease vs. Alloc Question

3 correlated questions:
1.Do the code snippets below provide the very same results in terms of memory?
NSBundle *bundle=[[NSBundle alloc] init];
[bundle release];
bundle=nil;
and
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
NSBundle *bundle=[NSBundle mainBundle];
[pool drain];
pool=nil;
bundle=nil;
2.Why in
NSBundle *bundle=[[NSBundle alloc] init];
[bundle release];
the retainCount of bundle is 1, not 0?
3.Which is recommended: always use class methods, or always gain ownership by using alloc?
Thanks.
Yes, those should be equivalent in terms of memory management, from the developer's point of view. The frameworks might be doing something behind the scene to hang on to [NSBundle mainBundle], but that's not your concern.
Ignore retainCount. waves hand That's not the method you're looking for. Once you have relinquished ownership of an object, either by invoking release or autorelease, then it is invalid (bad practice) to send more messages to that object. In your example, you alloc an NSBundle, so you own it. That means it has a +1 retain count (I say +1, because it's relative). When you release the bundle, it now has a "0" retain count, which means you no longer own this object (despite whether or not it may still exist in memory), which means you should not send messages to it, under penalty of stuff blowing up in your face.
What's recommended is to use whatever's appropriate for the situation. If you just need a temporary object, then using a class method that returns an autoreleased object is probably going to be just fine. If you need to be absolutely sure that the object isn't going to go away while you're using it, then you can use an alloc/init approach (or retain an autoreleased object) and then just release it when you're done.
In the second example you will create 1 extra object (the NSAutorealeasePool) and because of that the two are not exactly the same in terms of memory. But after the code runs I believe the memory will return to the same state in both examples. I am not really sure but I believe that in the second example bundle is an autoreleased object, so when the pool is drained it gets released.
I believe that when the object gets dealloc'ed the retainCount isn't changed.
It is usually recommended to avoid class methods when you create a lot of temporary objects because they won't get released until the next AutoreleasePool drain is called (and if you don't have an AutoreleasePool inside your method it won't happen for sure until you return from your method - and maybe even later). Otherwise you should use the one that feels better for you. I personally prefer allocating them. It is also important to remember that if you want the autoreleased object (the one returned from a class method) to stick around even after you return from the function to retain it.