iPhone: Confusion about NSAutoreleasePool - iphone

I read about NSAutoReleasePool and understand that it makes memory management easier on iPhone. It is available on NSObject so autorelease message available for every object instance. Moreover, I shouldn't use autorelease a lot as NSAutoReleasePool uses cache memory and you might runout of memory if there are plenty autoreleased objects. Is my understanding correct?
One thing I didn't understand is what is the purpose of creating NSAutoreleasePool explicitly like it's done in following method? What its purpose here? Is it like releasing imgData, img objects automatically? Because I could see that these objects are not released in this method.
- (void)loadImage {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *img = [UIImage imageNamed: #"default_user.png"];
if(![[imgURL absoluteString] isEqualToString: #"0"]) {
NSData *imgData = [NSData dataWithContentsOfURL: imgURL];
img = [UIImage imageWithData: imgData];
}
if([target respondsToSelector: action])
[target performSelectorOnMainThread: action withObject: img waitUntilDone: YES];
[pool release];
}
Thanks.

You can use local autorelease pools to help reduce peak memory
footprint. When your pool is drained, the temporary objects are
released, which typically results in their deallocation thereby
reducing the program’s memory footprint.
I can suggest this explicit autorelease pool was created for manage image loading. Probably that image has a large size (in Mb) and this pool can guarantee that memory will released asap. All autorelease pools organized in stack, so this inner pool will drain early than main pool.

The idea behind auto-release to keep the memory usage of the app low. You see if you haven't used this auto release then this data would have gone to the main autorelease of the app So even if you don't need this image further it still stays in the memory and increases its footprint. Creating a new auto release frees the memory straight away.(the size of the image can be huge.)

The rule is that you must create an autorelease pool in every thread that will use autorelease. In your example, img variable is autoreleased, and assuming the loadImage method is threaded, you must declare a new pool before using any autoreleased memory.

Related

iphone how to manage memory when frequently loading images

I'm currently coding my app that loads images frequently (but not the same images). As far as I test it out, there's no memory leak problem, but the memory usage of the app increases as I load up different images. It means the app will eventually gets killed by OS when it hits memory cap. I inspected through instrument and I found that a lot of memory was being held by NSConcreteData.
//from different thread, and pass data to main thread
NSData *data = [[[NSData alloc] initWithContentsOfURL:url] autorelease];
//at main, data to uiimage
imgView.image = [[[UIImage alloc] initWithData:data] autorelease];
When the view is dismissed and all allocated memories get return to heap, it seems like the memory
I allocate for NSData keep presents in the memory and therefore the memory usage of the app increases compared to what it was before it loaded images. I'm not sure if this is normal behavior.
Or is it bad practice to pass allocated memory between different threads?
This may or may not help in your exact case, but this is often reduced by paying closer attention to your autorelease stack growth. You should be able to reduce the problem by wrapping those heavy creators (data from url, image with data) in autorelease pool blocks.
#autoreleasepool { work with large NSObjects here }
or, depending on the system you must deploy for:
NSAutoreleasePool * pool = [NSAutoreleasePool new];
work with large NSObjects here
[pool release];
If you can use #autoreleasepool, do so. it's slightly better because it interfaces with the underlying autorelease stacks directly. If you need backwards compatibility, then use NSAutoreleasePool. At a higher level, they really serve the same purpose, in the sense that you should be able to interchange their implementations in your program without introducing new issues. Therefore, it really comes down to the minimum OS you are targeting and the build settings you have specified for your project when deciding which to use.
You should wrap your handling and creation of large (or many) allocations in autorelease blocks because autoreleased objects are sent release messages "at some point in the future". By creating and destroying that autorelease pool explicitly (and by using autorelease less often), you allow many of these objects to be destroyed much sooner.
As to why this can be good in addition to simply not using autorelease in your program: clients and system libraries may end up adding your big/numerous images/NSDatas to the autorelease pools. Autorelease pools are like (thread local) stacks -- when you destroy your local pool, all those autorelease messages made while your pool was on top will be fulfilled, and the autoreleased objects will receive their release messages.
Or is it bad practice to pass allocated memory between different threads?
Remember that you should message your UIKit and AppKit objects from the main thread. In Cocoa, many libraries may specify their threading models. NSData follows the Foundation threading model. The objects are not explicitly thread safe, but they are safe to use if you read and/or write from no more than one thread at any given time (that is, use a lock whenever you need to use it in a MT context, or pass copies). Passing and sharing data/objects is not a bad practice, it's necessary (or the logical solution) at times. There is a slight catch saying it's 'not bad': many people do not understand multithreading and shared resources well (it is not a trivial skill to learn for many).
Try something like this. Autorelease is less precise than explicitly releasing.
//on background thread data's retain count will now be 1
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
//on main thread (I'm assuming .image is a retained property)
UIImage *newImage = [[UIImage alloc] initWithData:data];
imgView.image = newImage;
[data release];
[newImage release];
try open Allocation to calculate memory,
and when every time you want to release something,
Make it to be nil first, make sure no one is using this variable.
Otherwise, it crash.
Make Variable equal to nil, before release.

How to handle leaks when using a multiple threads in iphone?

I have called a method in separate thread in viewdidload method
[NSThread detachNewThreadSelector:#selector(callWebService) toTarget:self withObject:nil];
-(void)callWebService{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSThread detachNewThreadSelector:#selector(loadImages) toTarget:self withObject:nil];
[pool release];
}
-(void)loadImages{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self performSelectorOnMainThread:#selector(reloadTable) withObject:nil waitUntilDone:false];
[pool release];
}
-(void)reloadTable
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[myTableView reloadData];
[pool release];
}
How to handle leaks while using thread? I want to use threads.
Errors
*** __NSAutoreleaseNoPool(): Object 0x604b830 of class NSCFString autoreleased with no pool in place - just leaking
*** -[NSAutoreleasePool release]: This pool has already been drained, do not release it (double release).
The autorelease pool must be drain, not release. So I think if you change it to [pool drain] it should be working fine.
Don't know if you found your answer yet, but as I had hit something similar to your problem, I did some looking. It seems that when you drain a pool, that is (effectively) equivalent to releasing it. The documentation on the class says:
Since you cannot retain an autorelease pool (or autorelease it—see
retain and autorelease), draining a pool ultimately has the effect of
deallocating it.
So, you should only drain a pool once. If you need another context after that point, you should generate a new pool in the same way you generated one earlier in your code.
If there is no pool available, then you can end up leaking (as you mentioned). However, autorelease calls should log a warning message in that instance. Regarding threads, the documentation has this to say
The Application Kit creates an autorelease pool on the main thread at
the beginning of every cycle of the event loop, and drains it at the
end, thereby releasing any autoreleased objects generated while
processing an event. If you use the Application Kit, you therefore
typically don’t have to create your own pools. If your application
creates a lot of temporary autoreleased objects within the event loop,
however, it may be beneficial to create “local” autorelease pools to
help to minimize the peak memory footprint.
Hope this helps.

Class Methods Used Many Times Cause Leaks?

Let's say I'm developing a game. I run the following class method thousands of times:
NSBundle *bundle=[NSBundle mainBundle];
I do not create an autorelease pool and release the objects that call the above class method all the time. I create an object, it calls the above class method, I release it, and on, and on, thousands of times.
3 questions:
Is memory leaked?
If I ran:
NSAutoReleasePool *pool=[[NSAutoReleasePool alloc] init];
[pool drain];
would it then effectively release all those NSBundles created in the class method?
if I wrote:
pool=nil;
instead of writing:
[pool drain];
Would the same effect be achieved? Is this good practice?
The three questions are correlated and I will boost the one that clarifies them :)
No, memory is not leaked. [NSBundle mainBundle] returns an autoreleased object, so the autorelease pool will take care of it. However, if you're going to call it a bunch of times in one function or something, you'd be better off either getting a reference to it once and just holding on to it while you need it, or creating your own autorelease pool.
Not exactly. Everything after NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; that is autoreleased will go into pool, and after you drain the pool, they'll be released. Note: [pool drain]; also releases the pool, so don't call [pool drain]; [pool release]; or you will send the release message to the object twice and probably crash.
No. pool = nil; would just lose the reference to pool and the actual pool object would be leaked. You have to call either [pool drain]; or [pool release]; and good practice would be to set pool = nil; afterwards.
If you do not create an autorelease pool, and one does not already exist, any objects that are autoreleased (either by you, or by other libraries you are using) will be leaked.
setting pool=nil; does nothing except leak the whole pool, perhaps if the pool was set in a property i.e.
#property(nonatomic, retain) NSAutoreleasePool *pool;
self.pool = [[[NSAutoreleasePool alloc] init] autorelease];
//now, self is the sole retainer of pool, so if self abandons it it gets drained:
self.pool = nil;
//pool's retain count drops to zero, pool drains.
If you are doing this thousands of times, it might slow things down to drain the pool every time, consider doing it every 5 or ten times, set a counter in the loop and when it hits some decided number, do this:
self.pool = [[[NSAutoreleasePool alloc] init] autorelease];
//this will get rid of the old pool and put in a new one, so you only have to get rid of the one remaining at the end of the loop.

Running out of memory with UIImage creation on an offscreen Bitmap Context by NSOperation

I have an app with multiple UIView subclasses that acts as pages for a UIScrollView. UIViews are moved back and forth to provide a seamless experience to the user. Since the content of the views is rather slow to draw, it's rendered on a single shared CGBitmapContext guarded by locks by NSOperation subclasses - executed one at once in an NSOperationQueue - wrapped up in an UIImage and then used by the main thread to update the content of the views.
-(void)main {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init];
if([self isCancelled]) {
return;
}
if(nil == data) {
return;
}
// Buffer is the shared instance of a CG Bitmap Context wrapper class
// data is a dictionary
CGImageRef img = [buffer imageCreateWithData:data];
UIImage * image = [[UIImage alloc]initWithCGImage:img];
CGImageRelease(img);
if([self isCancelled]) {
[image release];
return;
}
NSDictionary * result = [[NSDictionary alloc]initWithObjectsAndKeys:image,#"image",id,#"id",nil];
// target is the instance of the UIView subclass that will use
// the image
[target performSelectorOnMainThread:#selector(updateContentWithData:) withObject:result waitUntilDone:NO];
[result release];
[image release];
[pool release];
}
The updateContentWithData: of the UIView subclass performed on the main thread is just as simple
-(void)updateContentWithData:(NSDictionary *)someData {
NSDictionary * data = [someData retain];
if([[data valueForKey:#"id"]isEqualToString:[self pendingRequestId]]) {
UIImage * image = [data valueForKey:#"image"];
[self setCurrentImage:image];
[self setNeedsDisplay];
}
// If the image has not been retained, it should be released together
// with the dictionary retaining it
[data release];
}
The drawLayer:inContext: method of the subclass will just get the CGImage from the UIImage and use it to update the backing layer or part of it. No retain or release is involved in the process.
The problem is that after a while I run out of memory. The number of the UIViews is static. CGImageRef and UIImage are created, retained and released correctly (or so it seems to me). Instruments does not show any leaks, just the free memory available dip constantly, rise a few times, and then dip even lower until the application is terminated. The app cycles through about 2-300 of the aforementioned pages before that, but I would expect to have the memory usage reach a more or less stable level of used memory after a bunch of pages have been already skimmed at fast speed or, since the images are up to 3MB in size, deplete way earlier.
Any suggestion will be greatly appreciated.
I realize this is an old posting, but in case it helps anybody else .... This looks like a case of memory fragmentation. We have an app that behaves the same way. The amount of memory actually allocated by the app never reaches dangerous levels, but if you look at the amount of resident memory for the app (using VM Tracker snapshots in the Allocations Instrument, or the Activity Monitor Instrument), it climbs inexorably over time until a not-very-large transient spike kills the app.
The app in question is a multi-threaded app that makes tons of transient allocations in a large range of sizes, the timing of which can't be predicted or controlled. Such an app has to be paranoid about releasing unneeded memory allocations, not because they take up too much memory per se, but because they can create holes that prevent larger images from fitting into the allocated blocks. Even smaller allocations that tend to be overlooked are important in fragmentation (granted that the low-level allocator does group allocations by size, which is helpful to an extent). Memory zones are theoretically helpful for addressing fragmentation but pretty hard to make effective, at least in my experience. Also, use custom auto-release pools, or better yet, alloc/init as much as you can, and release as early as possible. The fact that the underlying frameworks are always making their own allocations for caching purposes probably doesn't help.

Whats the correct way to alloc a UIImage to memory and release it iphone

Using Instruments, I keep on getting pointed to a memory leak with a UIImage.
I think I'm assigning and releasing the memory correctly. The leaked object in instruments is described as NSConcreteData
Is the following the correct way to assign and release a UIImage?
UIImage* flagimg = [UIImage imageWithData: [NSData dataWithContentsOfURL:url2]];
[flagimg release];
flagimg =nil;
[UIImage imageWithData:] returns an autoreleased object, which should not be released by you again. So this code snipped contains not a memory leak but the opposite, a double free (in the worst case).
Note that Instruments sometimes generates false positives and/or reports memory leaks in the Foundation itself (yep, they make mistakes too :-).
The fastest way to alloc/release an object is to avoid convenience initializers (like imageWithData:) and instead to something like
NSData* data = [[NSData alloc] initWithContentsOfURL:url]];
UIImage* img = [[UIImage alloc] initWithData:data];
[data release];
// use your image
[img release];
This will allocate and release your object right away and not wait until the autorelease pool is cleaned.
But please note too, that a memory leak is generally not memory that is not yet freed, but that is lost and cannot be freed anymore, so an object which will be deallocated by the autorelease pool is not considered a memory leak.
as a general rule you can say
if you create an object an theres a "init","copy" or "retain" in it, you have to release it.
if not, you get an autoreleased object.
thats not always true, but in most cases
both imageWithData and dataWithContentsOfURL return autoreleased objects, so you should have no memory leaks in that code snippet.
Since flagimg is returned autoreleased, your [flagimg release]; call is not needed; you're over-releasing that object.