iPhone, Convenience Method or Alloc / Release? - iphone

Whilst developing for the iPhone I had a stubborn memory leak that I eventually tracked down to NSXMLParser. However whilst looking for that it got me thinking about maybe changing a lot of my convenience methods to alloc/release. Is there any good reason for doing that? In a large app I can see how releasing memory yourself quickly is a better idea, but in a small app is there any other difference between the two methods.
NSNumber *numberToAdd = [NSNumber numberWithInt:intValue];
dostuff ...
OR
NSNumber *numberToAdd = [[NSNumber alloc] initWithInt:intValue];
doStuff ...
[numberToAdd release];
cheers gary.

There is no difference memory-management-wise between those two methods. In a gui app, an NSAutoreleasePool is created and destroyed on every spin of the run loop, so small objects like this will most likely be destroyed within a few microseconds. The only time I could see it mattering is if you're on a secondary thread and you're about to create a TON of autoreleased objects. However, you're always welcome to create and destroy your own autorelease pools.

[NSNumber numberWithInt:1] === [[[NSNumber alloc] initWithInt:1] autorelease]
Even though numberWithInt: is more convenient, it is more code to execute. Internally, autorelease is sticking that object onto an ever growing array.
If you are in a loop doing lots of allocations, you might benefit from managing memory yourself. In the normal course of UI operations, the cost of autorelease is negligible.
The actual definition of lots is up to you and a profiler. At what point does the benefit of more readable code lose to the benefit of faster code?

Related

How can I keep memory usage low with a lot of NSStrings, or how do I release NSStrings?

I am working on an app that imports a (very) large csv file into Core Data for catching purposes. The process goes something like this:
Parse the file line-by-line into an NSMutableArray full of NSStrings
After X number of lines, import the array into Core Data (this involves manipulating and in some cases creating new NSStrings)
[NSMutableArray removeAllObjects];
Rinse and repeat
At first glance it looks like the memory should be freed up at the conclusion of each cycle. With large files, however, I am finding that the app crashes after signaling a couple low memory warnings. Running the leaks tool tells me that most of the memory is being used up by CFString objects, which I understand are related to NSString objects (although I don't know how)
I understand that NSString are reused whenever possible, and that they don't act quite the same as other objects where memory is concerned, although I don't understand any of the details. How can I reclaim the memory that my NSString objects are using?
Running the leaks tool tells me that most of the memory is being used up by CFString objects, which I understand are related to NSString objects (although I don't know how)
NSString is actually a class cluster. Although you think you are working with NSStrings, you are almost certainly really working with one of its subclasses. The Cocoa framework chooses which subclass to use depending on circumstances.
CFString is actually not really an NSString at all, it is the pure C string object used by Core Foundation. However, you'll find it is "toll free bridged" to NSString. This means that, to Cocoa, it looks like an NSString. The reason you are seeing lots of CFString usage is because whatever Cocoa API you are using to obtain these strings ultimately performs its work in Core Foundation.
Anyway, all that is irrelevant to your problem except for the fact, that lots of CFStrings more or less means the same as lots of NSStrings. What you need to reduce your memory footprint is nested autorelease pools as Girish has already said. As a first step, modify your algorithm like this:
Create a new autorelease pool.
Parse the file line-by-line into an NSMutableArray full of NSStrings
After X number of lines, import the array into Core Data (this involves manipulating and in some cases creating new NSStrings)
[NSMutableArray removeAllObjects];
drain the autorelease pool
Rinse and repeat (start at 0)
If this doesn't help, or only helps a bit, consider bracketing just the parsing with an autorelease pool.
I am assuming that you don't have memory leak.
If you are using too much autoreleased object this can happen
You try following
Create nested auto release pools --- some time happen that you have some long running loops where auto release object get accumulated. -- so add custom auto release pool to release the auto release object when you required.
Don't use autorelease object in the parsing cycle --- do manual object allocation and release once your work is done.
You can't sure that the memory is consumed by NSStrings only. I suggest you check it thoroughly. Try to go for "Build and Analyze" it will help you to find out leaks.
While using NSString object, instead of going for autoreleased objects like
[NSString stringWithFormat#""];
create your own object and release it as soon as you done with it.
NSString * string = [[NSString alloc]initWithFormat:#""];
//use string object
[string release];
this way you can be sure, that you releasing the string there itself.
or create an Autorelease pool
NSAutoReleasePool * pool = [[NSAutoReleasePool alloc]init];
// do you coding, creation of objects, releasing them, whatever...
[pool drain]; or [pool release];
Also have a look at these memory management tips

With obj-c on the iPhone, is there any harm in autoreleasing everything instead of releasing?

With obj-c on the iPhone, is there any harm in autoreleasing everything instead of releasing?
Eg, this code:
NSString *recipe = [[NSString alloc] initWithUTF8String:sqlite3_column_text(dbps,0)];
[arr addObject:recipe];
[recipe release];
Can be shortened to two lines by autoreleasing the recipe nsstring when i create it:
NSString *recipe = [[[NSString alloc] initWithUTF8String:sqlite3_column_text(dbps,0)] autorelease];
[arr addObject:recipe];
Are there any drawbacks to this? I find it suits my coding style better. Thanks all.
The drawback is that the objects get released later. In most cases this won't be a problem but if you allocate and autorelease thousands of objects in a tight loop this overhead can add up to a point where it impacts performance or even causes your app to run out of memory.
In any case, you might want to use:
[NSString stringWithUTF8String:sqlite3_column_text(dbps,0)];
instead of
[[[NSString alloc] initWithUTF8String:sqlite3_column_text(dbps,0)] autorelease];
If the object does not have a scope outside the function it is used, you should always release it in order to minimize the amount of memory consumed by your application.
If you let the object stick around until the autorelease pool kicks in, a lot of unneeded memory may need to be allocated. This is especially important with iOS 4 and fast app switching, where memory is also allocated to apps in the background.
The lower your own memory footprint is, the bigger a chance there is that your application will not be terminated when in the background in case memory gets tight.
Here is my understanding on the subject, I'm sure I'll get downvoted to death if I say anything wrong ;)
Generally speaking, in tight loops, init + release will be faster than autorelease. Most of the time performance is not an issue
You may not actually want to autorelease at all times. If you want an object to stick around, you'll need to manually release or stick your autoreleased obj in a property with a retain so that you can get at it later otherwise your obj will be released as soon as it goes out of scope
With manual init + release you have more fine grained control over what is happening, this may be useful for advanced multi-threaded scenarios (especially now that GCD is pervasive)
autorelease is probably fine most of the time so long as you understand how reference counting works, but do not treat it like a silver bullet. You can still leak plenty of memory using autorelease incorrectly.
I'll turn the question around: The main disadvantage with release is that it's very easy to forget. Assignment to a local or to an instance variable look pretty much identical (they're entirely identical if you don't assign in an initializer):
Foo * a = [[Foo alloc] init];
myFoo = [[Foo alloc] init];
This, and similar issues, leads to a bunch of potential problems:
When you copy-and-paste code, will you forget a release?
When you change between local and instance variables, will you remember to add/remove the release?
If an exception is thrown, does the code leak? (This is almost always true, but it is traditional to not care about exceptions in Obj-C.)
Personally, the overhead of a memory leak when you refactor code is worse than the overhead of a few autoreleased objects. I occasionally refactor code so it looks like this:
FooView * v = [[[FooView alloc] initWithFrame:CGRectZero] autorelease];
// set up v...
myFoo = [v retain];
Local variables are marginally more efficient.
If you decide that you don't need the instance variable anymore, you just need to comment out one line.
Views are pretty heavyweight, so the autorelease overhead isn't going to matter much
For completeness, if you're doing a bunch of things in a loop (e.g. test code), you can autorelease at the end of every iteration with something like this:
for (size_t n = 100000; n--; ) {
NSAutoreleasePool * pool = [NSAutoreleasePool new];
// ... allocate and autorelease some stuff ...
[pool release]; pool = nil;
}
If you're worried about efficiency, you can gain significant speedups using (e.g.) CFString functions — the Objective-C overhead is pretty significant for small strings.
Problem is when you do autorelease you're not actually releasing the object but adding it to the current autorelease pool. Object will be effectively released when you release that pool which is done every time through the main loop .
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
You can create you're own autorelease pool but I'm not sure it would be better than simply use release.

Autorelease: Use always when you've NARC'ed?

I know this question looks like a dupe: I checked and it's not
In talking about NARC, the author of this blog says, "Personally, I like to immediately autorelease anything I NARC-ed, on the same line." This goes completely counter to all the examples I've seen on the Apple site and in books, where autorelease is only used when the object must be returned and cannot be released immediately. In general, the idea is that autorelease is memory intensive and can gum up your program (though it makes code cleaner). From Appress Beginning iPhone 3 Development:
these objects can have a detrimental
effect on your application’s memory
footprint. It is OK to use
autorelease, but try to use it only
when you really need to, not just to
save typing a line or two of code.
I am not asking if autorelease is worse than explicitly calling release (it is), but rather:
In most 'normal' situations on iPhone, just how bad is it to replace a later release with an earlier autorelease (in the same method)? Also, in what situations would it be absolutely prohibitive to do this?
My guess is that, compared to using a garbage collector (as MonoTouch apps do sucessfully), autorelease will hardly make a dent in your memory footprint, and that Vincent's advice it right on, and can make for cleaner code and less accidental memory-leaks.
There's nothing wrong with using autorelease, but when you allocate objects in a loop, you should always call release explicitly.
Using autorelease:
for (int i=0;i<1000;i++) {
NSString *s = [[[NSString alloc] init] autorelease];
}
// at this point, there are 1,000 unreleased string objects in memory
Using release:
for (int i=0;i<1000;i++) {
NSString *s = [[NSString alloc] init];
[s release];
}
// at this point, no string objects are "alive"
As you can see, you have to be really careful when using autorelease in loops.
You should be aware how autorelease works. Each thread in your application normally has a single autorelease pool. Objects can be registered in the pool. At the time they are registered, the pool determines the stackframe they belong to and will automatically pop the from the pool whenever that stackframe is left.
While this may seem costly (and it certainly is compared to direct retain/release), I don't think it even close to the cost a generation mark and sweep garbage collector can have.
Where autorelease really shines is in all situations where exceptions may be raised and there's no try/catch around. Autorelease is definitely preferable to a direct release in such cases.
There are, however, situations where you should avoid autorelease (the same goes for garabge collected environments where you should try to avoid these situations too). Creating temporary, autoreleased objects in a loop which runs a huge number of times is such a scenario, which puts significant stress on a garbage collector or the autorelease pool.
Replacing release with autorelease should be avoided in worker threads that are very simple and can live without the overhead of an autorelease pool. So the guideline is: Whenever you can avoid it, you should, whenever you're unsure autorelease.

Suggest the best way of initialization of array ( or other objects )

I am a bit confused in the following two ways of initialisations.....
Way 1:
- (void) myMethod{
NSArray *myArray = [[NSArray alloc] initWithObjects:obj1,obj1,nil];
[self setClassArray:myArray];
[myArray release];
}
Way 2:
- (void) myMethod{
NSArray *myArray = [NSArray arrayWithObjects:obj1,obj2,nil];
[self setClassArray:myArray];
}
In way 1, I have used a alloc init method which is a instance method and as I have used an alloc statement I have to release the array myself.
In way 2, I have used a static method to initialze the array and as there is no alloc statement used I dont need to release the memory the system will take care of that.
Way 1, is time consuming and can to lead to memory leaks if not taken care
Way 2, is faster in writing and you dont need to take care of memory leaks
But , still i have seen the way1 used in standard source codes more often than the way2. I have no idea why people do this or if I am wrong at some place.
Answers and comments are oppenly invited. Please suggest the best programming practice.
Your second example uses a convenience constructor, which returns an autoreleased object. The question, then, is whether it's better to use autorelease or alloc/release. mmalc's answer on this StackOverflow thread explains the drawbacks of autoreleasing objects. (Basically, use alloc/release whenever possible.)
Also (this may be stating the obvious), some classes might not have convenience constructors, so when working with these you'd have to use alloc/release.
as i know,
[NSArray arrayWithObjects:obj1,obj2,nil];
returns an autoreleased object, smth like
[[[NSArray alloc] initWithObjects:obj1,obj1,nil] autorelease];
and I prefer not to manage memory with autorelease pool. maybe it's just a prejudice))
When using method 2 (autorelease) the object is released when the operating system feels it has no references.
But when using the manual release, as you typed in your code, you can release directly, or whenever you need to.
I usually prefer the second way, and if I recall correctly, this is also what the Apple docs reccommend (use autorelease where possible).
In Way 1 the memory gets released faster, so if you have a method that gets called in a loop or recursively, using autorelease may accumulate much memory, whereas alloc/retain will keep your memory footprint low.
On the other hand I assume that using autorelease is more efficient, because the autorelease pool can release a big chunk of memory at once, instead of small chunks again and again. Tough I may be wrong here.

Use autorelease before adding objects to a collection?

I have been looking through the questions asked on StackOverflow, but there are so many about memory management in Objective-C that I couldn't find the answer I was looking for.
The question is if it is ok (and recommnded) to call autorelease before adding a newly created object to a collection (like NSMutableArray)? Or should I release it explicitly after adding it. (I know NSMutableArray willl retain the object)
This illustrates my question:
Scenario A (autorelease):
- (void) add {
// array is an instance of NSMutableArray
MyClass *obj = [[[MyClass alloc] init] autorelease];
[array addObject:obj];
}
Scenario B (explicit release):
- (void) add {
// array is an instance of NSMutableArray
MyClass *obj = [[MyClass alloc] init];
[array addObject:obj];
[obj release];
}
I assume both are correct, but I am not sure, and I sure don't know what the preffered way is.
Can the Objective-C gurus shed some light on this?
IMHO, which way is 'right' is a matter of preference. I don't disagree with the responders who advocate not using autorelease, but my preference is to use autorelease unless there is an overwhelmingly compelling reason not to. I'll list my reasons and you can decide whether or not their appropriate to your style of programming.
As Chuck pointed out, there is a semi-urban legend that there's some kind of overhead to using autorelease pools. This could not be further from the truth, and this comes from countless hours spent using Shark.app to squeeze the last bit of performance out of code. Trying to optimize for this is deep in to "premature optimization" territory. If, and only if, Shark.app gives you hard data that this might be a problem should you even consider looking in to it.
As others pointed out, an autoreleased object is "released at some later point". This means they linger around, taking up memory, until that "later point" rolls around. For "most" cases, this is at the bottom of an event processing pass before the run loop sleeps until the next event (timer, user clicking something, etc).
Occasionally, though, you will need to get rid of those temporary objects sooner, rather than later. For example, you need to process a huge, multi-megabyte file, or tens of thousands of rows from a database. When this happens, you'll need to place a NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; at a well chosen point, followed by a [pool release]; at the bottom. This almost always happens in some kind of "loop batch processing", so it's usually at the start and bottom of some critical loop. Again, this should be evidence based, not hunch based. Instrument.app's ObjectAlloc is what you use to find these trouble spots.
The main reason why I prefer autorelease to release, though, is that it is much easier to write leak-free programs. In short, if you choose to go the release route, you need to guarantee that release is eventually sent to obj, under all circumstances. While this seems like it might be simple, it is actually surprisingly hard to do in practice. Take your example, for instance:
// array is an instance of NSMutableArray
MyClass *obj = [[MyClass alloc] init];
[array addObject:obj];
// Assume a few more lines of work....
[obj release];
Now imagine that for some reason, something, somewhere, subtly violates your assumption that array is mutable, maybe as the result of using some method to process the results, and the returned array containing the processed results was created as a NSArray. When you send addObject: to that immutable NSArray, an exception will be thrown, and you will never send obj its release message. Or maybe something goes wrong somewhere between when obj was allocd and the required call to release, like you check some condition and return() immediately by mistake because it slipped your mind that that call to release later on must take place.
You have just leaked an object. And probably signed yourself up to several days of trying to find out where and why it is your leaking it. From experience, you will spend many hours looking at that code above, convinced that it could not possibly be the source of the leak because you very clearly send obj a release. Then, after several days, you will experience what can only be described as a religious epiphany as you are enlightened to the cause of the problem.
Consider the autorelease case:
// array is an instance of NSMutableArray
MyClass *obj = [[[MyClass alloc] init] autorelease];
[array addObject:obj];
// Assume a few more lines of work....
Now, it no longer matters what happens because it's virtually impossible to leak obj accidentally, even under extremely unusual or exceptional corner cases.
Both are correct and will work as you're expecting them to.
I personally prefer to use the latter method, but only because I like to be explicit about when objects get released. By autoreleasing the object, all we're doing is saying "this object will get released at some arbitrary point in the future." That means you can put the autoreleased object into the array, destroy the array, and the object might (probably) still exist.
With the latter method, the object would get destroyed immediately with the array (providing that nothing else has come along and retained it in the meantime). If I'm in a memory-constrained environment (say, the iPhone) where I need to be careful about how much memory I'm using, I'll use the latter method just so I don't have so many objects lingering in an NSAutoreleasePool somewhere. If memory usage isn't a big concern for you (and it usually isn't for me, either), then either method is totally acceptable.
They are both correct but B may be preferred because it has no overhead at all. Autorelease causes the autorelease pool to take charge of the object. This has a very slight overhead which, of course, gets multiplied by the number of objects involved.
So with one object A and B are more or less the same but definitely don't use A in scenarios with lots of objects to add to the array.
In different situations autoreleasing may delay and accumulate the freeing of many objects at the end of the thread. This may be sub-optimal. Take care that anyway autoreleasing happens a lot without explicit intervention. For example many getters are implemented this way:
return [[myObject retain] autorelease];
so whenever you call the getter you add an object to the autorelease pool.
You can send the autorelease message at any point, because it isn't acted on until the application's message loop repeats (i.e. until all your methods have finished executing in response to user input).
http://macdevcenter.com/pub/a/mac/2001/07/27/cocoa.html?page=last&x-showcontent=text
You have alloc'ed the object, then it's your job to release it at some point. Both code snippets work merely the same, correct way, with the autorelease way being the potentionally slower counterpart.
Personally speaking, I prefer the autorelease way, since it's just easier to type and almost never is a bottleneck.
They're both OK. Some people will tell you to avoid autorelease because of "overhead" or some such thing, but the truth is, there is practically no overhead. Go ahead and benchmark it and try to find the "overhead." The only reason you'd avoid it is in a memory-starved situation like on the iPhone. On OS X, you have practically unlimited memory, so it isn't going to make much of a difference. Just use whichever is most convenient for you.
I prefer A (autoreleasing) for brevity and "safety", as johne calls it. It simplifies my code, and I've never run into problems with it.
That is, until today: I had a problem with autoreleasing a block before adding it to an array. See my stackoverflow question:
[myArray addObject:[[objcBlock copy] autorelease]] crashes on dealloc'ing the array (Update: Turns out the problem was elsewhere in my code, but still, there was a subtle difference in behavior with autorelease…)