Images not freed on memory warning when using [UIImage imageNamed] - iphone

In my app, I've used the line
[UIImage imageNamed:imageName]
whenever loading an image. As I understand it, this function caches images for later use - this is great, because most of the images are used more than once.
BUT - when I simulate a memory warning, the memory used by these images doesn't seem to be freed according - and since most of the memory is in fact used by the cached images, it is pretty important that any currently unneeded images are released from memory!
-
Is this the expected behavior, or do the images remain in memory due to the fact that it's only a simulated memory warning? Or, if I want to release these images, will I have to write my own category for UIImage that caches images but releases uneeded ones when memory is in short supply (or even better, has anyone already done this/shared the code for it)??

What I have done is create my own caching mechanism utilizing -initWithConentsOfFile which doesnt cache, and an NSMutableDictionary for storing, every image allocated is stored in the dictionary with the image name as the key. If a memory warning is reached you can release and nil the dictionary thus releasing all the memory allocated from the images.
This gives you complete control over the image caching. -imageNamed: uses its own caching mechanism that you have no control over when and where the allocated memory is released.
You should try this method as well.
EDIT: Heres my UIImage class extension (https://gist.github.com/2880240), overriding -imageNamed: with custom cache, upon receiving a memory warning you can simply use [UIImage freeCache]. Also included, is the ability to set autorelease on all images upon storing them in the cache, i.e: [UIImage setShouldAutorelease:TRUE]. FALSE by default.
Give it a try, Hope it helps!

If there is no more reference to the image it should get cleaned, don't worry about the internal caching mechanism (since its behavior is undocumented anyway). Do you have any code in place to remove any references (nil or release) to the images?

Are you using it in a UIImageView?
A lot of framework data is automatically managed with the app goes into the background. Data for images loaded with imageNamed: are discarded automatically, but UIImageView does not discard its data, so perhaps its the same with the low memory warning.
P.S.
If your app is suspended it won't receive the memory warning. And if its using a lot of memory then it'll probably be terminated. To reduce the chances of this (if its important) then you could use an NSPurgeableData which you store in an NSCache in order to flag stuff as being purgeable in the event of a low memory situation, the OS will then purge it for you.

Related

Cutting down UIImage memory usage

I'm trying to find ways to cut down memory usage for my app right now, and I have an idea regarding UIImages. I make pretty extensive usage of UIImages, some of them common to multiple views. Is it a lot more memory efficient to instantiate a single UIImage and then use a pointer to that same image throughout the app rather than allocating a new UIImage for the same image in each view? Or, is the OS smart enough to sort of automatically cache a UIImage so that it is only stored in memory once? (doubt that's the case but I have to ask)
Thanks.
Straight from UIImage apple reference docs for imageNamed:
This method looks in the system caches for an image object with the
specified name and returns that object if it exists. If a matching
image object is not already in the cache, this method loads the image
data from the specified file, caches it, and then returns the
resulting object.
You use a lot of images, so remember that [UIImage imageNamed:#""]; caches the images, so if you are having low memory problem use instead [UIImage imageWithContentsOfFile:#""]; that doesn't cache it. Maybe that can help you cut down memory usage.
When a view unloads set the GUI properties to nil in the viewDidUnload method of UIViewController subclasses.
Yes, it is more efficient to store a single UIImage and use pointers to it.
It is unlikely that the OS caches images in this way, and even if it did, using pointers gives you more fine control of when the image is released / deallocated so that you don't have to hope the OS is going to take care of it.

iOS4 calling ImageNamed: still leak or cause memory issue?

So apparently, my app crashes on ipod 2nd generation due to low memory issue. What I do was calling image on each view within scrollView + pageControl when user scrolls. And app crashed when it reached a particular point after got memory warning. I tried to free up view when I got warning but it still caused crash.
I googled about ImageNamed: and apparently there was issue within this api call, but most article said it was fixed in recent iOS version.
I fixed this problem with calling image imageWithContentOfFile instead imageNamed, but I'm wondering if ImageNamed still causes memory leak or not free up when it view is released.
imageNamed: doesn't cause a leak, but it is frequently misunderstood which is what leads to memory issues when it's used. It caches the uncompressed image after it is loaded, which means there are immediately 2 copies of that image in memory. If you use it for small, frequently used images (such as icons), this is great because the runtime doesn't have to fetch the file off disk - it's already available in the cache. Where this gets users into trouble is when they use imageNamed: to load a large image, say a 4MP image taken with a camera. That image takes up quite a bit of memory: 4 million pixels, types 4 bytes per pixel = 16MB of memory, TWICE. If you use that method to load images for your slideshow, photo sharing, camera app, or whatever, it adds up real fast.
So if those features don't fit what you need, use one of the other UIImage loading methods. You users will thank you.
Note: This information comes from the Apple Engineer which presented the UIKit rendering session (#121 I think it was). Hopefully my notes are correct :)

Memory [ Real RAM ] used by App on IPhone 4.0 on lauch and then using UIImageview

I have two queries
I was running a sample app which having single view controller in it implemented. When I check the memory using Instrument it was showing 3.66 MB
. Wondered why it is taking so much of RAM as there is nothing much heavy in app.
When I have added UIImageview with the Image having size of 25 KB,then Memory uses go to 4.24 MB
[ I come to know the reason behind is "image is unpacked 320*480*4 = 580 KB" but need to debug more on this & it remains in cache ]
Along this I have also observed two scenarios
When we uses api [UIImage imageNamed:aName] for loading image, then calling [UIImageview release] doesn't have any effect.
But When we use
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:aName ofType:nil]];
Some memory is cleaned up when I call [UIImageview release]
In my app , I am going to use lot of images and that will cause a low memory and will crash the app.
Please provide me some ref or path to analyse why this behavior.
Thanks,
Sagar
Trying to fit your app in memory is a losing game. It'll lead you down weird paths of trying to figure out which sort of device you're running on, swapping in and out resources based on that, etc, etc.
The better option is to design your memory structure for ditchability, and then support a fairly harsh ditching regimen when you're notified of low memory conditions. Go ahead and use memory--it's there for that--and let the low memory warning be your signal to prune out unused resources.
A lot of people seem to feel bad that their application generates memory warnings. That's silly. The design pattern here is, eat all you want, but respond appropriately when you're told you're overweight. Given you're running on a broad range of devices with a broad range of memory profiles (an iPhone 3G has 1/4 the RAM of an iPhone 4 for instance), the best way is just to be sensitive to when you've filled memory.
The main hurdle you'll encounter is recovering from having ditched data. I find what works best is to explicitly set UIImage objects to nil, and then test for nil before using them, reloading them from the bundle or the network or whatever if necessary.
All that said: [UIImage imageNamed:] supports ditchability, but you don't have control over it. When a UIViewController subclass gets a memory warning, it will ditch cached UIImages that you've created with that method, but nothing you can do will make them go away until then. Even assigning a tiny something to the UIImage in question won't help because it's cached associated with the "name" that it's "Named", not the object that it is assigned to. So that method is good for images you're going to reuse a lot, but even so, it will get pruned when the time comes, and you need to respond appropriately.
Images, loaded with imageNamed, are cached in memory by UIKit, and images, loaded with imageWithContentsOfFile are not.

Memory is increasing all the time in navigation based iphone app

I have a navigation based App with 5 ViewControllers. After inspecting the memory allocation with instruments i found out that memory is increasing permanently. The app starts up with 2 MB and after navigating through all 5 Navigationcontrollers it grows up to 10 MB and counting...
For every allocated object there is a corresponding release in my code (in dealloc or somewhere else), so obviously there are no memory leaks. Instruments also tells me that no memory leaks could be found.
How can I solve this memory problem? At some point of time, after navigating through the views forward and backward an out of memory warning occurs and the background image disappears (I do not deallocate the image so the iphone does it on its own).
How can i determine the source of the "memory leak" problem? Is it possible that images are cached somewhere and hold in memory as long as the app is alive?
I always alloc images like this:
UIImage *kaufpreisImage = [[UIImage alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForResource:#"kaufpreis_background_green18px" ofType:#"png"]];
The images are under the Resource folder.
I would very much appreciate your help! I can't find a way out of this!
Thank you very much in advance
Regards Phil
Edit:
The only problem remaining is when I try to send an email. I want to send an email which contains multiple html tables and images inside the email body. The images are base64 encoded. After sending multiple mails I recieve an out of memory warning, although I dealloc all the stuff (images, Numbers and so on) inside the sendMail() method.
Does anyone know if sending base64 encoded images leads to problems? Can anyone give me a hint how I can send images inside the emailbody (e.g. as background image inside a html table like style="background-url(data:image/png;base64,%#)")? To clearify, this works. The images are sent to the Client (tested on MacOS) but sometimes the memory problem occurs...
Thank you very much
You need to release those images once you take ownership of them.
Maybe you shall try the 'Heapshot' function in the Allocation tool. Simply take a 'Mark Heap' when your first controller is started then navigate on and again back. Take another heapshot. Repeat this process 8-10 times. In the heapshots list you shall see that some memory has been allocated between an heapshot and the following one (otherwise if the amount is small and tends to zero it is normal), try to inspect it in order to check if you allocate something that remains alive.
You are responsible for releasing the instances of UIImage if you have used [[UIImage alloc] init...] to create them.
If you are loading images from the main bundle, try using +(UIImage *)imageNamed:(NSString *)name. This UIImage returned is returned autoreleased, so you don't have to release, and there is the upside that UIKit handles caching when using the imageNamed method.

Would such assignment of image cause a memory leak?

- (void)viewDidLoad {
[super viewDidLoad];
landscape.image = [UIImage imageNamed:#"tenerife1.png"];
}
I assign a new UIImage to the image property of an UIImageView object. I am not sure if that would result in a memory leak?
No, it should not. The old image should be automatically released when you set the new one, and the "imageNamed" method uses autorelease, so you should be OK there.
hey take into account imageNamed has serious memory issues as you loose control over its cache - ie: once you are done with your image, you cannot reclaim that memory. a quick google search would let you know how many people have faced problems with imageNamed
i was at the apple iphone tech talks and the guy giving the presentation confirmed the same damn thing - he suggested using imageWithContentsOfFile instead of imageNamed
if you just have couple of small images, its fine otherwise use imageWithContentsOfFile even though its a bit slower - and implement your own caching logic - check this great link on how to do it here
It depends on how the image property is defined. If it's defined as retain or, I suppose, even copy, it should be fine. You'll end up trying to reference deallocated memory and crashing your program if it's defined as assign.
Not ordinarily, but it would depend on how you've defined landscape.image. See post above. Be careful with using a lot of these:
[UIImage imageNamed:#"tenerife1.png"];
Since there is a tendency for these images to fill up memory, without getting released.