iOS - Memory Management: Where is all this memory going? - iphone

I've got a fairly basic app that I'm updating - and as part of the update I'm implementing memory warning management.
When the memory warning method gets called, I release any view controllers not in use (and these in turn release any of their objects). Everything seems to work fine, there are no leaks etc as far as I can tell.
What isn't working:
Using the 'allocations' instrument, there is a lot of memory that isn't being released when a simulated hardware warning is called. Here's what I do when testing:
1 - start the app - this is the original jump in memory shown below.
2 - add a new view controller - this is the second spike.
3 - Return to the main view controller and simulate a hardware memory warning - this is the (small) drop in memory towards the end. This warning should completely release the additional view controller and associated objects.
Although everything is released, there is a lot of memory that remains. As far as I can tell, it's something like cached animations etc that iOS does. In a real low memory situation though, this should be released, and not stick around as this is where the majority of the memory goes.
How can this memory be released - or what am I doing wrong? Any pointers would be much appreciated - thanks!
-
EDIT: Thanks for all the answers so far! Although unfortunately I still haven't been able to solve the issue yet. Furthermore, the memory weirdness only seems to occur when using modal view controllers.
I've noticed that I actually have a background loading method for the extra view controller called when the app launches, to make things run smoothly. This indicates that the second spike in memory is completely due to something other that the view controller - maybe animations or something? Anyhow the problem still remains - what is this extra memory being used for, and how do I release it when I need to?
I could potentially create a mini project that exhibits the behavior if it would help. Thanks :)

Are you really sure you are not retaining your UIViewController or its objects? You shouldn't have to simulate a memory warning to see a decrease in allocations after releasing your controllers.
I attached a screenshot showing how my application looks after pushing and popping a UIViewController three times, using a UINavigationController.
EDIT
To answer your comments: UIViewController belongs to UIKit and is not thread safe, which means you should not be creating one in a background thread. This could potentially be the cause of the memory leak, since it will not be added to the main autorelease pool.

There's a really-really great screencast about memory analysis with Instruments from WWDC 2010. That's how I learned how to track similar issues.
You should check out http://developer.apple.com/videos/wwdc/2010/. To be specific http://developer.apple.com/videos/wwdc/2010/?id=311.

Related

iPhone memory not released after view unloads and dealloc, why?

I have been struggling with memory issues in my iphone app since weeks and haven’t been able to resolve the issue yet in spite of comprehensive research online.
Here is the case:
My application communicates with the Google Analytics API and is based on 3 basic views: Main view, setup view, and a tableview view that presents the data from google (with a custom cell). I have also constructed a custom class that fetches the data from google and then kills itself when done. All the data is stored in a singelton datacenter.
All views are initiated and then released as follows:
if (self.vVisitsTabelView == nil) {
visitsTabelView *initiatevisitsTabelView = [[visitsTabelView alloc] initWithNibName:#"visitsTabelView" bundle:nil];
self.vVisitsTabelView = initiatevisitsTabelView;
[initiatevisitsTabelView release];
}
[self.navigationController pushViewController:vVisitsTabelView animated:YES];
[vVisitsTabelView release];
vVisitsTabelView = nil;
The issue is that through every loading of the view memory increases, but when the view is popped it is not releasing memory although dealloc is being called and ALL instance variables are being released. This cycle happens over an over again (while re-loading the same view) and memory consumption becomes very high. After demanding use I even got to 200mb real memory and 320 virtual on instruments. Strangely a memory warning was received only once, however my app never crashed due to low memory and instruments indicates NO leaks.
After entering background the memory is slowly being released and used by other apps, however when I return to foreground memory is reclaimed back to the level before entering background (maybe form the virtual mem?). This process takes 9 seconds and in that time the app is frozen.
Any ideas how to attack this situation? I have searched everywhere and carefully followed all guidelines.
Any lead is highly appreciated...
Please excuse me if I didn’t follow guidelines, this is my first time on this wonderful place.
Thank you, can you elaborate slightly more how to do it?
Yes; you have a memory leak. Now, the Leaks instrument may or may not tell you what is leaking. It won't detect objects that are still somehow connected to the rest of the application; i.e. if a reference to the object is retained in an NSMutableDictionary somewhere that is still in use by the app, it won't be detected.
Since you know exactly which object is being leaked, it is a matter of figuring out what has retained it, but not released it. The Allocations instrument provides for exactly this capability. Specifically, you can configure the Allocations instrument to track retain counts.
This article may help http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/.
Also, there are a number of very similar question/answers on SO that address this. There is one in the last couple of weeks that I can't find that gave a great pictorial tutorial of how to do exactly what you want.
Have you checked the retain count on your views? [theView retainCount] will do this.
Either way you should strongly consider moving to ARC which is new for iOS5. You should be able to say goodbye to all your memory management woes.

iOS UITableView random crash

I have a problem I can't locate clearly, maybe you can help me...
I have an iPad project, based on UINavigationController, most (but not all) of controllers inside are instances of UITableViewController, and everything works well...
Everything excepting that my application crashes randomly, sometimes after 10 minutes of use, sometimes after only 10 seconds...
It never crashes on the same view, never at the same time, making that difficult to reproduce.
In addition, it only seams to happen on device, I've never got this crash in the simulator.
The debugger doesn't help me very much, here is what it says:
-[UITableView autorelease]: message sent to deallocated instance 0x8e9800
And here is the call stack:
http://i.stack.imgur.com/JSCHx.png
Any idea ?
Thanks (and sorry for my english)
You're overreleasing a UITableView somewhere in your code. Are you calling release or autorelease on the UITableView inside one of your UITableViewControllers? You should only release objects that you 'own'. You get to own an object by using methods beginning with alloc, new, copy, or retain.
Please read the cocoa memory management guidelines for more info.
Useful links:
http://www.cocoadev.com/index.pl?MemoryManagement
http://www.cocoadev.com/index.pl?RulesOfThumb
At some point you are either releasing a UITableView instance that you do not own or you are failing to retain one at some point where you keep a reference to it (e.g. you store it in an ivar or a property declared assign rather than retain).
I have written about how to debug things like this on my blog:
http://loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html
Basically, try these three things first:
Do a Build an Analyze and fix everything you see
Turn on Zombies, run your code -- it will tell you if you talk to dealloced objects
If that fails, try Debug Malloc, but that's way harder.
I apologize, after re-reading all my source code, I found ONE ViewController (I have around 20 ViewController), where I released an Outlet, in ViewDidUnload.
The reason that it crashed randomly is that I didn't understood well the mechanism of ViewDidUnload, it is called to release views (but not objects of controllers) when memory is low and view is not visible (ex: First ViewController of a NavigationController), and the views are re-loaded when the ViewController become visible again...
In simulator, memory is rarely an issue so ViewDidUnload is almost never called...
Problem fixed, thank you everyone for your help
To help with making sense of the trace, see iOS Debugging Magic (Technical Note TN2239) and Understanding and Analyzing iPhone OS Application Crash Reports (Technical Note TN2151).
Jeff

viewWillAppear / viewWillDisappear not called....my answer to this

I have been struggling with this issue for a while and i noticed that many people came across the same thing by reading many posts here and on other forums. Just this morning i realised what i was doing wrong and i thought of sharing it just in case someone stumbles over it in the future.
the problem in my implementation was that within viewDidLoad of view controller (VC1) i was setting its view property to a new view controller (VC2) which forces i believe the framework to exit viewDidLoad of VC1 without reaching its end, hence not calling the consequent delegate function of the view controller: viewWillAppear, viewWillDisappear, viewWillAppear, and viewWillDisappear!
So my solution was to delay all the code that has to do with creating and setting VC2 to be called from within viewDidAppear instead of viewDidLoad. If you do it from viewWillAppear you will get to the same trouble.
Hope it helps
AF
Why would you go to all this bother just to save the memory of a UIViewController?
sizeof(UIViewController) gives 132 bytes. Even knowing that a view controller will create a fair few support objects so it's going to take up more memory than that this is a fantastic example of premature optimization.
I'd give it a fair chance that the code solution you have gone for will :
(a) leak memory in edge cases
(b) fail on further updates to iOS
(c) be a nightmare to debug by any coder other than yourself
(d) be a nightmare to debug by yourself in more than a few weeks
Why not just write your app using the frameworks provided and profile it - if this tiny amount of memory is causing you problems the fine, implement your solution. If not, leave well alone.

What to do when my app receives memory warning?

What should I do when my app recieves a memory warning?
It all depends on your app, usually you don't have to do anything special except following Apple's recommended practices.
ViewControllers which are not visible at the moment will get didReceiveMemoryWarning message. By default (calling [super didReceiveMemoryWarning]) controller's view is unloaded (released, freed). As the view is unloading, view controller receives viewDidUnload where you should release all your IBOutlets (or otherwise retained UI elements). Only then the view can completely be deallocated and memory freed.
In the didReceiveMemoryWarning you should also free as much data as you can - if you store some part of data model in ViewController, release it, and reconstruct in viewDidLoad that would be called when your view is loaded again (when user navigates back to this controller). You can inform your model classes to free memory too.
It really depends on your app.
If your app downloads and caches lots of contents from Internet for example, you should purge as much as possible when receiving a warning.
If your app is an OpenGL game, you might have a texture/sound/data manager which references some unused data, which you then want to free. Cocos2D manages this kind of things.
If your app isn't memory intensive, you have a memory leak somewhere, and you should 1) read the Memory Management Programming Guide by Apple 2) use Instruments/Leaks.
In didReceiveMemoryWarning, you should release any cached or non-essential items to prevent running out of memory completely.
If you log or write to any other file, there might be an issue with "disk" space.
Also you should check for memory leaks.

iPhone dev - In didReceiveMemoryWarning or every time

In a multi-view application, do you think its better to let views automatically get unloaded in memory tight situations, or to actually only ever have one View Controller allocated at a time, and when you switch views, the new one is created, the old one removed, the new one adde d and the old one released. Deallocating every time also means that there is a slight delay when switching to a new tab (very slight). So What do you think?
Also, I'm a bit confused about how and when and where and by who views are released (through viewDidUnload) automatically. If someone could clarify that for me, thanks.
In general, don't unload views unless you have to (didReceiveMemoryWarning) or it makes sense (something like a login form that's unlikely going to be used again).
You can't really assume that you have a fixed amount of memory. iPhone's have less memory than iPod touches. iPhone 3GS's have more memory than either. Jail-broken handsets often have substantially less memory.
By only releasing views when you have to you're making your app run faster on the 3GS and allowing it to run when there's less memory available.
The didReceiveMemoryWarning method releases the view if it is not visible. The following is from the documentation (v3.x):
The default implementation of this
method checks to see if the view
controller can safely release its
view. This is possible if the view
itself does not have a superview and
can be reloaded either from a nib file
or using a custom loadView method. If
the view can be released, this method
releases it and calls the
viewDidUnload method.
Obviously you also need to release any cached data. SDK2.x does not have the viewDidUnload method.
Depends, if you have a bunch of Views that the user switch back on forth from often then I would say to keep those in memory at that time, if theres views where the user wont come back to for awhile then you can probably unload that viewController and save memory. However if you have views that are taking up a ton of memory each then it might be wise to unload the viewcontroller when its not in use. Its really a matter of how often you are going back to the views and how much memory the view takes, also how many views you have. Taking these things into consideration you should be able to make a good decision of when to keep the viewControllers around and when the unload them. I believe that the view is a round as long as the ViewController is around (unless u release it explictly, which might have bad side effects (dont know)) , viewdidUnload just tells you that the view was unloaded of the screen, not too sure on that point tho.