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

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.

Related

UIViewController does not release memory the first time

Got the weirdest thing happening ... I have a pretty complex UIViewController subclass of which I'm loading through a NIB file.
I push the view by simply doing the following:
SecondViewController2 *secV = [[SecondViewController2 alloc] initWithNibName:#"SecondViewController2" bundle:nil];
self.secondViewController2 = secV;
[secV release];
[self.navigationController pushViewController:secondViewController2 animated:YES];
[secondViewController2 release];
secondViewController2 = nil;
As you can see I release secondViewController2.
The thing is, when I perform it the first time, ALTHOUGH dealloc method is called in secondViewController2, I still observe in instrument an additional 2MB which do not seem to get released. There are no leaks of any sort, I checked already.
When I perform the below action the the second, third, fourth time etc. the dealloc is getting called and I DO NOT OBSERVE ANY ADDITION in memory. That alone convinces me that I do not perform the error in my code since the same code is being run the first, second third time but only the first time around 2MB are not being released. As I stated dealloc for secondViewController2 is still being run!!!
Any idea? is it bug in Apple's mechanism ?
First off, it is not possible to answer thoroughly your question without analyzing your complete implementation. But, generally speaking, if I understand correctly your question, I would say that the situation you are describing is a correct one.
You should think that there are actions that definitely have a permanent effect on memory occupation.
E.g., if you load some images into memory through [UIImage imageNamed]`, then your image will also go into an image cache which will not be emptied when the class that loaded the image is deallocated. Another good example is that of a singleton: a singleton class occupies some memory the first time it is instantiated and it usually never releases it (before the program ends - and when I say singleton, read also any kind of static globals).
Those are just 2 examples, but there could be many more cases of this. And it could be done in your own code, but it could also be done by some framework that your controller uses. This effect would be more likely if your controller is the first controller you instantiate in you app that uses some kind of functionality. But basically, it cannot be known before hand, I would say, but only after inspection of your program behavior via Instruments.
The really valuable information for you is that upon successive instantiation/deallocation of you controller class, the memory occupation does not grow. Generally speaking, this is a sign of two things:
your class has no memory leaks;
your class has not abandoned memory.
What 1+2 implies is that the overall memory consumption of your program (as far as your controller is concerned) is flat. (although it has a cost that you pay on first use).
So, in my view, your issue is at most one of "optimization" of memory usage by your controller. As I said, one should know exactly what your controller does to know whether those 2MB comes from some cache, or whatever else (and in some cases it could be not under your control either).
Hope it helps.

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

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.

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 images still stored in memory?

So I have several viewControllers, each creates images using "imageWithContentsOfFile" in order to conserve memory and then sets objects to nil and releases them in the dealloc method. There are no memory leaks. The problem is memory still builds up when switching views. So for example I'll be in view1 and it'll be using 8MB of memory and then I'll switch to view2 and back to view1 again and it'll be now using 10MB of memory. I've checked allocations in instruments and it's the images using it. Is there something I need to do to flush the memory out or something?
Thanks in advance!
Shouldn't you be calling [object release] before setting object = nil?
Sorry, I'm at home and I don't have a mac here so I can't test what happens when you do it the other way around.
Also, by saying there are no leaks, did you check using the Leaks tool? I don't think the tool detects all leaks, as I've tried putting a leak on purpose but Leaks wasn't able to see it.

release does not free up memory in low-memory condidtion

I am trying to follow the Apple's recommendation to handle low-memory warnings (found in Session 416 of WWDC 2009 videos) by freeing up resources used by freeing up my dataController object (referenced in my app delegate) that contains a large number of strings for read from a plist:
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
[_dataController release];
_dataController = nil;
NSLog([NSString stringWithFormat:#"applicationDidReceiveMemoryWarning bottom... retain count:%i", [_dataController retainCount]]);
}
But when I run ObjectAlloc within Instruments and simulate a Low-Memory Condition, I don't see a decrease in the memory used by my app even though I see the NSLog statements written out and the retain count is zero for the object. I do pass references to the app delegate around to some of the view controllers. But the code above releases the reference to the _dataController object (containing the plist data) so I would expect the memory to be freed.
Any help would be appreciated.
Are you sure that app delegate is the only owner of _dataController? -release only decreases the ref count, it won't deallocate the object unless the ref count drops to zero.
If _dataController is owned by other objects too, send a message to them to release it.
I am double-checking that. Thanks for the input! I did reread the memory management docs from Apple and I did put an NSLog statement in the dealloc method of my DataController and it is being called. I also put wrote out the retain count before the release and setting to nil of _dataController. The retain count is 1.
So this drives me back to why I am not seeing a significant decrease in memory usage. I think I need to understand the ObjectAlloc display in Instruments better and where the largest allocations of memory are taking place in my app. After searching for help in this area, I am frustrated with trying to determine from Instruments where this occurs. I can see that there is 3.54 MB for "All Allocations" and 608 MB for Malloc 32.00 KB. If I drill down on Malloc, I only see the Responsible Caller as being framework calls like png_malloc and inflateEnd. I am looking for calls within my code that is responsible for the Malloc but I don't see that. All this to say that I wonder if I am releasing the object or objects that will really make a significant difference in the amount of memory used for the low-memory condition. I think I need an in-depth tutorial for Instruments. The Apple help docs are okay but an example with code would be more helpful.