Memory usage accounting in a navigation controller-based app; - iphone

I have a navigation controller-based application that could be active for a relatively long time and can load multiple screens, revisiting some in the course of its life - a business application. When I push a screen I allocate some memory; when I go back (pop it) I need to ensure memory is not lost.
Now in Leaks I have a clean slate. No memory leaked, not so hard to do with the 10.6 static analysis feature and confirmed using instruments. Checking manually, I am sure I am releasing everything allocated in viewWillAppear in viewWillDisappear; everything allocated in viewDidLoad in viewDidUnload; everything allocated otherwise in dealloc.
I have used NSZombiesEnabled in development but I definitely do not have it active now.
When running under Object Allocation however I see memory usage growing. On entering a new view I see memory increasing but not decreasing by the same amount when navigating back. Nor is this simply the system failing to deallocate immediately, when left for some time memory remains static. This behavior is seen on every view.
What techniques can I use to isolate this memory? Should I be aiming for the application returning to some baseline after every view? How can I isolate reporting of memory used by subsystems such as Core Data, where I rely on faulting to load objects and should not be trying to manipulate them explicitly, and the code over which I have full control?

It is natural that the navigation controllers memory footprint grows as you push views to it.
If you are using Core Data anyways you could persist the state of the entire application to Core Data each time you push or pop a view. This way nothing will be lost.
The navigationController manages the memory for the viewControllers, so if you exceeds the iPhones memory it will then start deallocating the viewControllers. Core Data manages memory pretty aggressive so it is a good way to go.
By this approach I think you will utilize the memory management of the framework instead of trying to roll your own and potentially introducing long terms memory bugs:)
I would go for something like an Entity per viewController, and an Entity that saves the context in which the were loaded. This way you could just test to see if the framework has deallocated any of your viewController and then restore the navigationController stack if it did.
Hope this was at least something to consider:)

Related

Reducing memory usage by dividing .xib files?

I'm going back through one of my old apps (my first, actually), and am trying to reduce memory usage in order to stop it from crashing on older devices (I've run it on an old device and profiled with instruments, and it is definitely memory issues that cause it to crash). Unfortunately, when I made the app, I was not very familiar with the common practices of iOS development and structured it very poorly: with one view controller, and one xib file, hiding and showing interface elements as necessary.
Now I am wondering whether it would be worth doing a complete overhaul and starting over, with multiple classes and view controllers, and whether that will reduce the insanely high amount of memory (70+MB) needed to load the app.
Also, would it work if I just emptied out the .xib file and loaded all the interface elements programmatically (and continued using one .xib file)?
It's hard to know how much it will help without knowing what's really going on in your app. Here's some general tips to help you out though:
Split out your view controllers so you have one view controller per view. There are cases where a view controller should actually control multiple views (either for memory efficiency, performance, etc), but use this as a starting point.
Don't put all of your objects in a single XIB. Split it out so you have one XIB per view controller and let iOS load your XIB elements when needed.
Creating interface elements programmatically isn't going to help with memory usage.
Watch what you cache and only keep things in memory if there's a clear performance advantage.
If you decide to rewrite your app, be sure to profile it often using Instruments to measure your progress.

Memory crashes in iOS with real memory usage only at 5megs

I have been hunting down memory leaks for some time in my app. As of right now, as I flip back and forth between two views while watching the memory monitor instrument, the real memory fluctuates between 5 and 6 megs. This is all fine -- as far as I can tell everything is getting released properly when I pop back off a view. However, the virtual memory continues to increase and my available real memory drops rapidly every time I push the view back onto the view stack (even though the real memory usage of the app isn't increasing). Eventually, this all leads to an out of memory crash. Is this a telltale sign of any specific issue, or am I just missing a memory leak somewhere?
EDIT: The odd part is, I get an out of memory crash while the app is still only using up about 5 megs of real memory.
Do not use -retainCount.
The absolute retain count of an object is meaningless. It is an implementation detail. It may be influenced by many factors well beyond your code.
You should call release exactly same number of times that you caused the object to be retained. No less (unless you like leaks) and, certainly, no more (unless you like crashes).
See the Memory Management Guidelines for full details.
In this specific case, you are leaking memory but in a way that leaks can't find it. The objects that are leaked are still connected to your overall application's object graph somehow. Maybe through a notification, maybe through delegation, doesn't matter -- leaks sees the reference and concludes that the object might still be live.
Use the Allocations Instrument. Configure it to only track live allocations (since you don't care about objects that have been deallocated). Do some stuff with your app. Check out what Allocations knows about and explain why all those objects should stick around. You can use the data mining facilities to filter down to just your objects.
Anyway, you can also use the "Build -> Build and analyze" option to find suspicious non-conventional code.
Another reason why you may have memory lost in lower API layers is if you don't remove all your views from your view hierarchy (aka : not calling [view removeFromSuperview] everywhere). At least that's what seemed to have happened to me.
Note that most of time this isn't required, as you would simply release the main view and all its subviews, then rebuild it from the view controller when needed. Things start to get more tricky when you're not releasing the whole hierarchy but instead simply remove some of them from the hierarchy.
In that case, I came to the conclusion that you may have buffers or layers still cached in lower API parts, and in that case your Allocation instrument won't help you.
In order to monitor correctly you'll need to use the "Memory Monitor" (in System). You'll see that the "Physical Memory Free" line dropping close to 0 is the most reliable indicator that a Memory Warning will be issued.
Another advantage of using this instrument, is that you can attach it to a running process, thus making it possible to have console output and instrument running together easily.
Circular references also won't be counted in Leaks but you can track those in Allocations. Best bet is to fire up Allocations and get to a state where you think everything should be gone (or certain objects should be). If they're hanging around go dive in to them and look at where they've been retained and sort out the proper memory ownership/releasing.
As for Allocations, there are some things that it doesn't track that can affect the overall memory. Some of the things include some CGImage backing stores, some CoreAnimation stuff and some database stuff.
Have you used the "Leaks" Performance Tool? And check out the logs in Organizer to see if there's anything there.
Also look into the dealloc for the view controllers and make sure you are properly releasing all of it's objects?

IPhone memory problems

I am working on an App that is already been made but Memory Management was not considered in the development stages.
So what can I do to keep the App memory usage low as soon as I get a memory warning?
Is there any general tool or some piece of code that I can use to release any unused memory?
Two things.
First, if you're using any sort of view hierarchy (tab bar, UINavigationController, or something you've rolled on your own), the message is going to propagate upward. That means one handler for memory messages in your root-level UIViewController subclass can handle memory events for the whole app, which is very handy.
Second, you want to go after the low-hanging fruit. In the app I'm currently working on I have a couple different arrays of dictionaries that contain my app data, and each of those dicts contains both a thumbnail and a larger image. Obviously those make up the bulk of the bits I'm keeping in memory. So the first thing my root view controller does when it gets a memory warning is go through those data sets and set those images to nil. Because they're retained properties, they get released when the setter is called and the images are freed from memory. Then I have functions in my view controllers to notice the nil-ness of those image fields and reload them from the server.
By the way (okay... two things and a "by-the-way"), memory warnings aren't a problem. Some people seem to feel bad about getting them, want to redesign everything about their app so they never get one. That's really not necessary; even the best-designed app will get warned about memory occasionally, just because of the unpredictability of the background apps on the device. The important thing is to handle them well.
Xcode can be combined with the Instruments tool to show you the places where your application is leaking memory, i.e. where reserved memory is not released properly. CIMGF has a solid tutorial on this: http://www.cimgf.com/2008/04/02/cocoa-tutorial-fixing-memory-leaks-with-instruments/
You should have a look at the method
- (void)didReceiveMemoryWarning
of your UIViewControllers. This method is called when you receive a memory warning. Here you can release objects currently not used. But it's your part to determine what is used and what not.
The "Build and Analyze" feature of XCode is a tool you could use to see if the code contains any obvious memory leaks.
You should have a look at the small section "Memory Management" in the UIViewController class reference:
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html
Also an important document is the "Memory Management Programming Guide":
http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

If I CFRelease() an image in core data, how do I get it back?

My iphone app plays a slide show made up of 5 user images.  These images are stored using core data.  I was noticing that memory was building up every time a different slide show was played and it was not releasing any of the previously played slide shows.
 
These images are showing up in Object Allocations as CFData. So I tried releasing this data in the dealloc method
CFRelease(slideshow.image1);
CFRelease(slideshow.image2);
CFRelease(slideshow.image3);
CFRelease(slideshow.image4);
CFRelease(slideshow.image5);
This releases the previous slideshow great...BUT when I go back to view that same slideshow again, it crashes.
 
I am guessing that I need to alloc/init these images again, but I am not sure how?  Or maybe I should be managing this memory in a different way?
It sounds like you're CFRelease-ing data that you shouldn't, and since you're mucking around with the NSManagedObject, you inevitably get a crash when Core Data goes "WTF?"
By "it was not releasing" are you seeing a memory leak, or simple memory usage growth? If the former, then we'll need more information, especially if Core Data is leaking, you might need to file a bug report (which is unlikely). If the latter, then there's much you can do, since Core Data is in charge of its own memory management.
It's possible you could use a NSAutoreleasePool to optimize but I can't say more on that.

Which memory is released by didReceiveMemoryWarning/viewDidUnload?

My iPhone application is running into problems when deployed to the device, principally because I haven't handled memory warnings thus far (no problem in the simulator, with 4GB of ram on my dev machine!). No problem there, I just need to handle these warnings more skilfully (less suckily...).
Question is, which memory does the runtime release... just the view and subviews? I suspect that it is just these, but want to be sure that the runtime will not dereference any of the objects or memory in my controller (ie. not in the view).
Subquestion: if it is just the view and subviews, do I need to do anything special in viewDidLoad to make sure that when the view is brought back into memory the view shows correct data, or is it all handled automatically via my IBOutlet-s?
There are potentially many things that the view, or its subviews, may cache - such as image data. These are the sort of things that will be purged.
Anything specific to your application that you can afford to flush you'll need to do yourself by handling that callback.
However, this may be more of an indication that you are either leaking memory or not being as efficient with it as you might be. It's certainly worth running the app in Instruments with the Leaks tool, as well as running with the CLANG compiler's static code analyser. Also, examine your code to see if you are holding on to blocks of memory you don't really need - whether you can compress images more etc.
Remember, before the 3GS or the latest iPod touch, system memory was 128Mb but you should only count on having about 25-30Mb available to your application
Neither viewDidUnload nor didRecieveMemoryWarning automatically release anything. You need to override both of these methods.
Generally, viewDidUnload should release anything in the view that wasn't created in IB, and that you can reasonably deal with reloading when the view is loaded up again.
And didRecieveMemoryWarning is a message that is sent to your app when the system is running low on memory. When your app receives this message, you should release anything and everything that you don't immediately need, or risk the system forcibly shutting down your app.