Recently when I looked into iPhone memory management, I tried to compare the convenience method and init method on the same object. For example, I have UIImageView where it displays a downloaded NSData:
Convenience method:
imageView.image = [UIImage imageWithData:[downloads dataAtIndex:0]];
init method:
UIImage *aImage = [[UIImage alloc] initWithData:[downloads dataAtIndex:0]];
imageView.image = aImage;
[aImage release];
When I try to go back and forth on the views to increase the memory usage and hit "Simulate Memory Warning", the memory usage for the app went from 20MB to 18MB with convenience method, and init method went from 20MB to 13MB immediately.
I also waited and interacted with the app to give time on releasing on the convenience method's autorelease. But it didn't drop much.
Other than the autorelease vs release, what else contributed the difference?
Your autoreleased objects created by the convenience methods will not be released until the containing autorelease pool is drained. It is advisable to wrap memory intensive operations inside of an NSAutoreleasePool block if you will be making heavy use of them.
The only difference that could be causing this is that imageWithData: doesn't use the system image cache, while initWithData: does. So maybe the image that's made with the initializer can release it's image data when it receives a memory warning since it can go back to the system cache, while the one that's created by the convenience method can't.
Objects created with convenience methods are autoreleased, as I am sure you are aware. However, if you have no AutoReleasePool in the RunLoop where you are creating the image, then the object will be added to a non-existent pool, and never properly cleaned up. This may be the case if you are running in a thread, and have forgotten to create an AutoReleasePool for that thread.
To verify if this is the case, you could run Instruments (Leaks) and see what it reports.
Something that I have noticed is that with autoreleased objects, under memory pressure, there is a system GC that occurs with a noticeable performance hit if you don't release your pools in a timely fashion.
Also, using the init / release method allows your memory consumption in loops to remain flat, while using a autorelease pool creates spikes. In some memory challenged contitions, the rapid increase of objects in the autorelease pool may cause your application to get booted before the system takes steps to clean up stuff like emails being open, mobile safari tabs, and iTunes stuff running.
Bottom line, I tend to use init more because it makes my application's memory consumption more consistent and I see fewer problems with getting booted randomly. The gradual increase in memory consumption lets the daemons clean up the system without killing my app. Finally, as somewhat of an aside, if you are using the #property keyword in your classes, you have to be careful with stuff like:
myProperty = [NSMutableArray arrayWithCapacity:10];
Because what will happen is when the pool in your main.m class gets collected that item will be gone, causing a crash due to calling a method on a released object. If you are setting it with #property (nonatomic, retain) you will want to use:
self.myProperty = [NSMutableArray arrayWithCapacity:10];
to make sure it hangs around. You can avoid all of that by just going with alloc init however. Just watch your reference counts to make sure you don't have double references causing memory leaks.
Related
I have a question regarding autorelease pool and memory deallocation in an app I'm working on. If anyone needs to see the code I can post it.
First and foremost I'm using ARC in this app, now basically I'm allocating a good bit of memory on start up (images for an intro animation), and the memory they take up doesn't seem to properly deallocate until I receive a memory warning for one reason or another, or if I enter the background and re-enter the foreground of the app.
I've been monitoring the amount of memory being allocated in code as well as in instruments so it seems that this issue isn't some false positive. I know for a fact I'm properly disposing of the image memory as I clearly set the UIImageView.animationImages property to nil as well as set the UIImageView to nil and release it's parent view controller from memory once the animation is done. Basically, everything it has to do with is set to nil or removedFromSuperview to be sure that ARC knows it should be released.
Is there any way I can purge this autoreleased memory pool similar to the result of entering the background of the app or receiving a memory warning?
Figured it out, the UIImages I was allocating for my intro animation were being cached via imageNamed: method, therefore were retained even after they were autoreleased for some time.
To fix this I'm using imageWithContentsOfFile: method which does not cache the images.
How to solve memory allocation in ios ?give me the right way to solve memory issues and memory leaks.
The best way to avoid these Memory issues is through proper coding. Just go through the Apple reference on Memory Management.
You only release or autorelease
objects you own.
You take ownership of an object if you
create it using a method whose name
begins with “alloc”, “new”, “copy”, or
“mutableCopy” (for example, alloc,
newObject, or mutableCopy), or if you
send it a retain message.
You use release or autorelease to
relinquish ownership of an object.
autorelease just means “send a release
message in the future” (specifically:
when the used autorelease pool
receives a drain message—to understand
when this will be, see “Autorelease
Pools”).
Without more info all I can say is...
Release anything you init and/or alloc that is not autoreleased.
Delete anything that you call "new" on
free any data you malloc
Use Instruments to diagnose where your leaks are occuring.
Release anything you retain
release anything you init that is not autoreleased.
#Nipin, For solving memory issues, you'll have to release each object that you're allocating... ie, use [yourObject release]; for each object you call alloc method... Also, unload any textures that you're using [texturename unload];
[texturename release];
Do all these when you no longer requires those objects or textures and in most cases it can be where you exit from the scene...
follow the below link memory management
another link is small guide for quick point small article
My App tends to crash alot... :(
I know i've been making mistakes in deallocating the views and objects.. I just wanna knw apart from deallocating the memory in the last, how can i manage memory in between the code...
Also my most of the viewcontrollers uses -(void)ViewDidLoad to create the views..so shud i use -(void)ViewDidUnload too before deallocating the memory???
If yes, then plz guide me how to use it??
Also is there any other way to solve memory issues??? :(
Keep in mind that viewDidLoad can be called multiple times, this is especially true in low memory situations where view's can be automatically unloaded to save memory.
In this case you can either check if your object is nil before allocating it, or deallocate it in a memory warning (in didReceiveMemoryWarning, if self.view.superview == nil then things will be automatically released).
You should also get to know the profiling tools at some point, or at least the leaks profiler. In Xcode go to Run -> Run With Performance Tool -> Leaks. There are some issues with this tool you might hit, but once you come to grips you'll wonder how you lived without it (For instance if your host name has special characters in it you'll need to rename it).
If u have created any object in .h file and allocated it only once then u should deallocate that object
in this method:
-(void)dealloc
{
[myObject release];
[super dealloc];
}
but if u have created any object locally (in .m) file then release it at the place where it is not required any more.
I am developing an application which has almost 12 view controllers. Application has tabBar with 4 tabs means four view controllers and there are multiple views to navigate in each tab bar. Please note each tab has a navigationController with a rootviewController being its firstview. Application is an extensive database application. When I run on simulator it works nice but get didRecieve memory warning while running on the device. I have few questions regarding the same.
NOTE: I have checked the application using Instruments tool for Leaks and there are no red pyramids which means there are no leaks in the code.
What is the best practise when you deal with multiple view controllers.
when I recieve memory warning, I call [self deleteObjects] which deletes all the instances which are retaning the values for the current controller. But I am not confident if this the right way. What should be done when we recieve memory warnings. Is there any good tutorial for that. (Links plz)
Also how to make sure that the [self deleteObjcts] is not called for the visible controller.
(I was calling the deleteObjects method in viewDidUnload method before but since we do [super didRecieveMemoryWarning] it breaks the code as viewDidLoad is called in hierarch from top to bottom so once I deleted object for top viewController obviously there will be error for rest of the controllers.)
Some of the basic confusing questions for me are as follows:
Why the memory warnings are not consistent. Like I get them sometimes at the start whereas sometimes there are no warnings.
When we used [NSDate date], [UIImage imageNamed:#"..."], [NSString stringWithFormat] etc, we dont own these objects and we dont have to release them but how can we make sure these objects are relased when we recieve a memory warning.
I am using NSMutableArray at multiple places. In this arrays I store the [NSString StringWithFormat ], [UIImage imageNamed...] objects, so when I realease the arrays do I need to relase the objects in the arrays though I dont own them.
Though this is a big list of question but I appreciate your help and time since I am in last stage of my development I am facing these major challenges.
You receive memory warnings when you run out of memory. Memory is not only taken by your App, all other running processes use memory and the memory being used may always vary.
Those object are all autoreleased. The NSAutoreleasePool will take care of releasing the objects, you should never release such an object yourself (well, not as long as you have not retained it yourself). This doesn't really matter, autoreleased object will be released quite quickly.
When putting an object in an array, it will be retained. When you release the array, it will send release all it's children objects. As you store autoreleased objects in the array, they will take care of their own releasing. This has probably already happened when you release the array, so -dealloc will be called on all the objects immediately.
NSMutableArray *someArray = [[NSMutableArray alloc] init];
NSDate *date = [NSDate date]; // Autoreleased object. Retain-count is 1
[someArray addObject:data]; // The array retains the data object. Now has a retain-count of 2
// Some other things
// The date object has been called release at some time (because it was autoreleased)
// so date now has a retain-count of 1
[someArray release] // Will release all containing objects thus date will be called dealloc
I've run into memory problems with UIImage imageNamed that I think are caused by the OS caching images and not releasing them when it should. There are lots of other developers who have seen the same thing.
I would try using imageWithContentsOfFile instead of imageNamed and see what happens.
For example forPNG images --
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"filename here" ofType:#"png"]];
Here's a thread that covers what I'm talking about:
I have been tracking down why NSObject references, while being explicitly release, still show up in ObjectAlloc. In fact, have reduced down NSObject to a basic shell, with a [[myObject alloc]init] immediately followed by a [myObject release], and it does not look like it is being released in ObjectAlloc. This is a big problem with a NavigationController app that pushes/pops multiple view controllers, as the recently popped viewcontrollers aren't being released, because of these 'unreleased' NSObject references. Hmmmmmm.
I could put my code up here, and have a bunch of 'have you's that never get anywhere. Autorelease pools, blah blah.
So, let's look at the Sample 'SeismicXML' sample app from Apple... fire it up in ObjectAlloc/Leaks. Very basic in getEarthquakeData:
XMLReader *streamingParser = [[XMLReader alloc] init];
[streamingParser parseXMLFileAtURL:[NSURL URLWithString:feedURLString] parseError:&parseError];
[streamingParser release];
I see a TON of junk laying around in ObjectAlloc from XMLReader, despite releasing it. I bet if we put a 'refresh' button on this app to call 'getEarthquakeData' again, we would crash the app within 5 refreshes.
Any thoughts?
I think you are confused about the ObjectAlloc instrument which will show all object allocations for the lifetime of your application. It's main use is to track memory usage over time.
The instrument I think you want is the one that is called Leaks which shows you what memory is being leaked by not having any reference to it. That is pointers to objects not being sent release-dealloc before they are reassigned.
There might be an autorelease pool holding onto the object. If you create many autoreleased objects without cleaning them out of the pool, you'll get leaks until you return to the outer loop with the autorelease pool.
Here's how autorelease pools work: in the main loop, there's an autorelease pool. Everything autoreleased goes there. At the end of every loop iteration, all the objects in the pool get released. If you allocate objects in another loop somewhere, they won't actually get released until you return to the main loop. Unless, of course, you create your own autorelease pool just for the loop.
Another problem could be that your object is never released. If you get an exception between +alloc and -release you'll get a leak. A way to fix this is to use instead:
[[[XMLReader alloc] init] autorelease]
Finally, you could be working with garbage collection here. I don't know enough about the GC system to tell you what behavior you should expect.