views:

706

answers:

4

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?

+1  A: 

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.

Mike Akers
+1  A: 

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.

Airsource Ltd
if there's no autorelease pool present, you should get warnings printed to the console when you try to create an autoreleased object, fyi.
Ben Gottlieb
It should be on main thread so it may not be related...
leonho
+3  A: 

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.

wisequark
+1  A: 

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.

Heat Miser
CG on iPhone? Tell more...
Roger Nolan
Not GC really, that is what I call the system sweep that collects the default Autorelease Pool around the application. Since it is a sweep for dereferenced objects that you don't really control, I think of it as a really rudimentary garbage collector
Heat Miser