iPhone performance optimization best practices [closed] - iphone

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I was looking for a book, text, post or something talking about iPhone optimization but I couldn't find anything except for Apple documentation.
I think it would be great to talk about which are the common steps you do when optimizing your apps performance. I'm now trying to improve my app memory usage and I've figured out it is really difficult when your app is complex.
How do you handle view creation and destruction? Are you doing it by yourself or do you delegate on iPhone navigation controller?
Do you use any trick to free some memory in your app?

To optimize the memory usage, avoid using auto-released objects.
If you don't need an object anymore, release it explicitly, so the memory will be reclaimed immediately.
Otherwise, the object will stay in the pool for an unknown time.
Note that this will optimize your application's memory usage, but not the performances.
Releasing explicitly objects may slow down your application.
You'll sometimes have to decide if you want a faster application, or an application that uses less memory.
Also try to use C code whenever possible. For instance, if you just need to store objects in an array, don't use a NSMutableArray unless you rely on a particular method.
If not, use 'id *' variable, and use malloc() and free().
Hope this helps a bit... : )

If you have a loop which might be executed many times over, it might be worth it to manually manage the NSAutoreleasePool in that case. More often than not you end up with a lot of auto-released objects (remember Foundation etc. generate auto-released objects, too) and waiting for your thread to end or control to return to the run loop could cause memory problems and slow your application. There is no guaranteed recipe for success here, so you might have to probe a bit.
One of the huge memory eaters are images, and everything that has to do with them. If you have a UITableView with hundreds of rows and each cell containing an image, you might not want to keep them all around in memory. You could keep a cache of those images in the file system and load the images as needed. Disk I/O might be relatively expensive, but if you watch the memory notifications closely and read ahead wisely, you'll hardly notice a performance impact.
Key techniques to remember when trying to reduce your app's memory usage are using the static analyzer (Cmd+Shift+A) and Instruments, especially the object allocation instrument.
One thing I try to force myself to do is avoiding instance variables whenever possible. They make your code harder to maintain and consume memory because they're usually not deallocated until their owner. Try to avoid unnecessary instance variables, or try to release them early if they can be recreated (from disk, for example).

Related

How to fix memory leaks in iOS applications?

I have found few memory leaks when I am running my application. For your reference, I am sharing the screenshots of Instrument debug logs and also Xcode Debugg memory graph tool. I am not getting what is going wrong here. Please help me to resolve memory leaks.
Please help me to fix the memory shows in the image. Thank you.
I know this is an old question, but a few observations.
When you have a lot of objects that are leaking, focus on high level objects (especially your own classes). We do not care why the array was not released. We care about why the item that is keeping a strong reference to it was not released. XTubeManager and GlueTubeManager are probably good places to start searching, but I don't know what other high level objects appear in the panel on the left.
When you have leaks, it is very useful to use the “Malloc Stack Logging” feature. So edit your scheme (command+<; or “Product” » “Scheme” » “Edit”) and go to the “Diagnostics” section and temporarily turn on “Malloc Stack Logging”:
Then, when you select a leaked object, you can see where it was instantiated but using the memory inspector panel on the right:
Look for entries in that stack trace that are white (your code), as opposed to all the system items that are in gray. When you hover items in that stack trace, there is even a little arrow that lets you jump to the code in question. In my example, the leaked object was instantiated in viewDidLoad.
This will not tell you why it leaked, but you will be able to see where the object in question was instantiated in your code, and you can start your investigation from there, diagnosing why an object created at that point in your code still has lingering strong references.
Remember to turn off the “Malloc Stack Logging” feature when you are done with your diagnostics.
As an aside, when we see URLSession objects that were not released, that begs the question of whether you instantiated a URLSession object (rather than using the shared instance) and neglected to call finishTasksAndInvalidate. Ideally, you would have a single URLSession and reuse it for all network activity (or use the shared instance), but if you must instantiate sessions, make sure to invalidate them when you are done.
You do NOT need to use Instruments. That's the old way. Use Xcode itself.
See Visual Debugging with Xcode
- 24:45
Watching the video is a MUST, but the summary of the video is as such:
There are two type of memory problems. You just have to repeat a flow in your app 2-3 times to be certain the memory graph has caught it
Leaks. Xcode will annotate this with purple icon. Possible are: delegates, closures
Abandoned memory. Xcode will not annotate this. But it's still increases your memory footprint. possible examples are: A repeating timer that is never invalidated, NotificationCenter, A never ending DispatchWorkItem
For Leaks the memory graph is a loop ie two way.
For Abandoned memory the graph is NOT two way. It's just an object one that Apple categorizes as 'root path' referencing your object and never letting it go. For more on this see here
In this case, just because some tool says you’ve got a memory leak doesn’t mean you have one. The amount of data seems to be less than 1MB, that’s nothing. Your tool suspects there’s a leak because data was allocated and not released, but these are single objects. Quite possible that memory is going to be released or reused later.
Use your software for hours and check if memory usage gets larger.
Memory on mobile devices is a shared resource. Apps that manage it improperly run out of memory, crash, and suffer from drastically decreased performance.
so to fix it follow this steps
Open Xcode and build for profiling.
Launch Instruments.
Use the app, trying to reproduce as many scenarios and behaviors as possible.
Watch for leaks/memory spikes.
Hunt down the source of the memory leaks.
Fix the problem.

CFString Memory Management Issue

I am developing an app for the iPhone and am encountering some memory management issues. During execution of the app the live bytes continuously increase without bound. I have tried to track down the issue within my code but cannot seem to find anything that would cause the live bytes to increase so dramatically. The one thing that I have noticed during execution is that the allocation for CFString(Immutable) increase the most rapidly and never decrease or stay constant. Does anyone have any idea why this may be happening? All that the app is doing during this execution is populating a table view from a local array or strings, then downloading another array of string objects and populating a different table view. I am using ARC.
Given the lack of anything concrete to go on, I'll give you somewhat general counsel:
See Finding leaks with Instruments for guidance on how to use Instruments to find leaks.
For specific advice how to go from you allocations, to a more meaningful analysis of the source of those allocations, see point #4 of this Stack Overflow answer. In short, highlight one of your unexplained jumps in allocations, set the bottom window to show you the call tree, hide system libraries, and see in which of your routines the memory is being consumed.
Also, don't overlook the static analyzer, which is especially important if you don't use ARC, or if you use any Core Foundation calls.
Are you doing anything with Core Foundation functions? If so, you obviously need to know that you either have to explicitly transfer ownership to ARC (with either CFBridgingRelease or __bridge_transfer) or manually call CFRelease. The static analyzer of my prior point would point this out to you, though.

CCNode/CCSprite/Box2D memory performance questions (cocos2d,iphone)

is it enough if I set the visibility to NO on my CCNode/CCSprite? Is it still in the memory?
What's the best way to remove it from memory and than put it again to it (fast)?
What about b2Body's? How to do that on them?
I want to do this because I splitted up my level and I just want to put the objects into memory which are visible....
Setting a node/sprite to invisible will definitely not free it from memory. If you want to remove it from memory completely and add it in again quickly I suspect a memory pool is the best way to do that.
I'm not sure I understand why you want to have only objects that are visible in memory and then be able to quickly add them into memory again quickly? It's likely I just don't follow what you are trying to accomplish. You may be trying to optimize your memory usage to prematurely. Certainly you should stop all memory leaks but have you done any profiling as to how much memory your project is using?

Why is autorelease especially dangerous/expensive for iPhone applications?

I'm looking for a primary source (or a really good explanation) to back up the claim that the use of autorelease is dangerous or overly expensive when writing software for the iPhone.
Several developers make this claim, and I have even heard that Apple does not recommend it, but I have not been able to turn up any concrete sources to back it up.
SO references:
autorelease-iphone
Why does this create a memory leak (iPhone)?
Note: I can see, from a conceptual point of view, that autorelease is slightly more expensive than a simple call to release, but I don't think that small penalty is enough to make Apple recommend against it.
What's the real story?
(cannot accept your own answer?)
Well, after all that, I did manage to find a reference from Apple Developer, added as a side-note near the bottom of the page:
iPhone OS Note: Because on iPhone OS
an application executes in a more
memory-constrained environment, the
use of autorelease pools is
discouraged in methods or blocks of
code (for example, loops) where an
application creates many objects.
Instead, you should explicitly release
objects whenever possible.
Still, this suggests using autorelease carefully, not avoiding it altogether.
(and now for my comment)
It sounds like there is a certain amount of overhead in maintaining the pool. I read this article which would lead me to probably avoid autorelease as much as possible because I prefer things to be consistent. If you have some memory under autorelease and other memory being totally manually managed it can be a bit more confusing.
It is not the question to use or not to use autorelease, because in some cases autorelease is the only way you'll get through. The question should be "Why not to use autorelease on all objects, instead of using retain and release?".
To answer that, you should first learn what's a proper use for autorelease. Let's say that you have a class that has two properties: firstName and lastName. There is a getter and a setter for each. But you also need a method that would return fullName, by concatenating these two strings into a brand new string:
- (NSString *) fullName {
NSString str = [[NSString alloc]initWithFormat:#"%# %#", firstName, lastName];
// this is not good until we put [str autorelease];
return str;
}
What's wrong with that picture? The reference count on the returned string is 1, so if you don't want to leak, the caller should release it when he's done. From the caller's point of view, he just requested a property value fullName. He is unaware of the fact that he got a brand new object that he should release after usage, and not some reference to an NSString internally held by the class!
If we put the [str release] before return, the string would be destroyed and the method would return garbage! That's where we use [str autorelease], to mark the object for release at a later time (typically when the event processing is done). That way the caller gets his object, and does not have to worry whether he should release it or not.
The convention is to call autorelease on a new object before the method returns it to the caller. Exceptions are methods with names that start with alloc, new or copy. In such cases the callers know that a brand new object is created for them and it is their duty to call release on that object.
Replacing release with autorelease altogether is a bad idea, since the objects would pile up and clog the memory very quickly, especially in loops. The resources on the iPhone are limited, so in order to minimize memory hogging, it is your duty to release the object as soon as you're done with it.
I disagree that avoiding autorelease altogether is wise.
Cocoa Touch uses it quite frequently internally and for many situations it's the only way to allocate memory properly (a good example is reusable table view cells). If you understand what is happening, the autorelease pool is a great tool at your disposal. The main thing to remember is that the blocks are not freed until some point later in the run loop. If you are running a tight loop without user interaction and are piling up autorelease blocks, you will eventually run out of memory.
Autorelease is not a substitute for garbage collection (not available on in the iPhone SDK) and can lead to nasty dangling pointer bugs (the pointer still seems to be good, then at some unpredictable point goes invalid), but is also very useful in writing clear and easy to maintain code. Consider the following case:
[aDictionary writeToFile:
[documentsDirectory stringByAppendingPathComponent:#"settings.plist"]
atomically:YES];
The path string is generated as an autorelease object. We aren't required to create a temporary object, so we avoid that overhead (and the possibility we might forget to release it). The memory will be fully released (no leaks), just that it will happen later in the run loop. Ask yourself: am I going to allocate hundreds of these before I get back to user input? If no (as would be the case here), autorelease is a great solution and indeed this NSString method for working with paths is only available using autoreleased memory.
I do agree with the above poster that following convention and being consistent is a very good idea.
I tend to avoid using autorelease on the iPhone where I can (as Jon points out, you can't always do without it), simply because I like to know that the objects I'm working with are released the instant I don't need them. Memory constraints are one of the largest problems you'll face on the device and I believe they're the source of most of the crashing issues you'll find out there.
As highlighted by Apple, a particular area of concern is when you use autoreleased objects within any kind of loop, because they'll pile up within the autorelease pool. You then have to manage when to drain the pool or create / release one. Doing that every pass through the loop might degrade performance, but going too many passes without could lead to dangerous memory usage. I'm still tweaking this in Molecules, because there are intermittent memory issues when importing large (>2 MB) text files from the Protein Data Bank. I was able to improve performance by minimizing autoreleased objects, but couldn't eliminate them completely.
Another area to watch out for is using autoreleased objects with threads. If at all possible, do not use autoreleased objects when dealing with methods performed on a background thread, because the pool can be drained at random times. This leads to intermittent crashes that can be really fun to track down.
I would highly suggest avoiding autorelease like the plague. Memory management bugs are a great way to waste massive amounts of time and money, I've had the dubious honor of going through the process many a time on old Mac apps, and the fact that the iPhone has tight memory constraints mean that you have to be extremely careful, or the app will just be unstable and crash often...like so many of the first apps that were released last summer.
The only reliable way I've found to write stable iPhone applications is to manage all your memory yourself, and do it consistently. Even if you are the only programmer on your project, you'll thank yourself later. It can be difficult if you learned to program in languages that "take care of everything for you," but it really is worth learning how to do well if you are serious about createing quality iPhone apps.

Best approach to debugging applicationDidReceiveMemoryWarning on iPhone?

Need advice on how to debug this. I'm new with limited environments and have no previous embedded or smart phone programming experience so I could use some clues.
Already aware of:
Instruments, Clanger Static Analysis, manual code review, etc. Instruments seems to be very helpful in general but quite time consuming and freezes up a lot of the time! Clanger has also helped me a lot as well. It seems like I'm just consuming too much memory in general and I'm wondering what a good strategy is. Do I release some top-level objects? Is there a 'preferred strategy'?
Just wondering if anyone has tackled this successfully and if they have any other suggestions? Thanks all.
There are a lot of good articles for memory management in an iPhone app. Here are some useful links.
http://iosdevelopertips.com/objective-c/memory-management.html
http://kosmaczewski.net/2009/01/28/10-iphone-memory-management-tips/
https://cocoa-touch.blogspot.com/2008/09/memory-management-on-iphone.html
Things you should in general take care of
Release any variables which you do not need
Always handle didReceiveMemoryWarning and release any variables not in use
Stop any memory-heavy processes in applicationDidReceiveMemoryWarning like audio/video playing, UIImagePickerController etc
EDIT
This does not apply any more. imageNamed: had caching issues prior to 3.x OS versions. The issue does not exist any more and you should use imageNamed: (makes implementing retina display easier)
Do NOT use imageNamed: to create UIImage objects.
Basically you're receiving this warning because (unsurprisingly) the iPhone is dangerously low on memory. This can generally be for one of two reasons;
You have a memory leak.
You are allocating far too many objects and need to revisit your design.
For the first one you should run instruments and examine your memory allocations. This can really slow down your app (and requires additional memory) so try testing areas of your app one at a time. E.g. if you have multiple views switch between them a couple of times.
For the second you will have to examine things you are doing that could result in large memory allocations. For example if you're writing a Flickr browser you might need to cut down the number of images you have loaded at anyone time, or free up some unused ones when you receive this warning.
These are about the only general rules I can suggest without knowing more about your app.
Unfortunately there's no real way (that I know of) to get figures for current memory allocation from the iPhone OS. This makes it really difficult to isolate the areas of your application that are inadvertently memory hungry.