Still pain with memory debugging.
I have 4 VC's I load by using navigation controller. Every VC has its own PNG images used for several controls.
In Instruments I realized that most of the VM regions are occupied by ImageIO_PNG_Data.
And as I push/pop VC's those VM increases and never decrease (I was supposing that dealloc some VC would also release images).
Of course, the debug is done in the Simulator.
To expand slightly on rokjarc's comment:
UIImage +imageNamed: explicitly caches. The documentation states:
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.
So images loaded previously will remain in the cache unless or until the memory is needed elsewhere. There's no efficiency to be gained from freeing memory up needlessly.
If you want to avoid the caching for whatever reason — I would argue whatever spurious reason — you could use +imageWithContentsOfFile:, or the normal init equivalent, having obtained the full path from NSBundle.
PNGs set to image views and other places via the interface builder will be accessed via the cache as far as I'm aware.
If the VM allocations do not have physical memory allocated to them there is no problem.
iOS memory maps files and there may be no physical memory allocated at any given time. Some VM allocations are frameworks that are shared by other apps.
What you need to watch are Living Heap Allocations which in this case is a little over 4MB.
Related
I am making an app where I am displaying a lot of images, for example a profile image for a player object. I have all the images stored in Media.xcassets, and the images are named after the name of the player object they belong to.
playerImage.image = UIImage(named: playerName)
I have found that after I've loaded an image, the memory usage goes up permanently, although the image is no longer displayed. It can for example go up 3/4 Mb, while the image file is just around 50kb. Even after I leave a viewController it seems the memory use from the displayed image is still there. (I am using unwind segues, so there isn't stacking of UITransitionViews)
(The increases in memory use come when I am displaying images that haven't been displayed before)
Eventually the app crashes when the memory reaches around 1GB. Is there any way to fix this, or reduce memory use?
I had the same problem just last week. What I did is to change all:
UIImage named
to:
UIImage imageWithContentsOfFile
The memory allocated with the first method seems not to be released by the Garbage collector, whereas the memory allocated with the second one yes.
Im not a swift master, but I think this will work:
UIImage(contentsOfFile: (Bundle.main .path(forResource: "imageName", ofType: "png"))!);
Hope this helps.
My app is saving and retrieving data from Parse.com. And showing images, buttons, scrollviews, etc.. (the normal stuff). Then when I got near finishing my app, it started to receive memory warnings and the app started crashing often. I checked it in the Instruments and noticed the live bytes was extremely high at some points, and I can't figure out why.
Is the app crashing because of the high live bytes? What should value of the live bytes be?
Obiously something is going on in the VM. But I have no idea what this is. What is the VM: CG raster data? And this: VM: CG Image? I am not using CGImages only UIImages
Is the app crashing because of the high live bytes?
Yes.
What should value of the live bytes be?
There's not fixed number. The limits change from OS version to OS version, and sometimes depend on the device and what else is going on at the moment. The right thing to do is (a) try not to use so much, and (b) heed the warnings and dispose of stuff you don't need.
Obiously something is going on in the VM. But I have no idea what this is. What is the VM: CG raster data? And this: VM: CG Image? I am not using CGImages only UIImages
A UIImage is just a wrapper around a CGImage.
You have too many images alive at the same time. That's the problem you have to fix.
So, how many is too many? It depends on how big they are.
Also, note that the "raster data" is the decompressed size. A 5Mpix RGBA 8bpp image takes 20MB of RAM for its raster data, whether the file is 8MB or 8KB.
I still feel the number is too high though, or is 30-40 MB an okey number handling 3-6 full-screen sized images at a time? This is when tested on a 4 year old iPhone4, iOS 7. If that matters.
On an iPhone 4, "full-screen" means 640x960 pixels. 8bpp RGBA means 4 bytes per pixel. So, with 6 such images, that's 640*960*4*6 = 14MB. So, that's the absolute minimum storage you should expect if you've loaded and drawn 6 full-screen images.
So, why do you actually see more than twice that?
Well, as Images and Memory Management in the class reference says:
In low-memory situations, image data may be purged from a UIImage object to free up memory on the system. This purging behavior affects only the image data stored internally by the UIImage object and not the object itself. When you attempt to draw an image whose data has been purged, the image object automatically reloads the data from its original file. This extra load step, however, may incur a small performance penalty.
So think of that 14MB as basically a cache that iOS uses to speed things up, in case you want to draw the images again. If you run a little low on memory, it'll purge the cache automatically, so you don't have to worry about it.
So, that leaves you with 16-24MB, which is presumably used by the buffers of your UI widgets and layers and by the compositor behind the scenes. That's a bit more than the theoretical minimum of 14MB, but not horribly so.
If you want to reduce memory usage further, what you probably need to do is not draw all 6 images. If they're full-screen, there's no way the user can see more than 1 or 2 at a time. So, you could load and render them on demand instead of preloading them (or, if you can predict which one will usually be needed next, preload 1 of them instead of all of them), and destroy them when they're no longer visible. Since you'd then only have 2 images instead of 6, that should drop your memory usage from 16-24MB + a 14MB cache to 5-9MB + a 5MB cache. This obviously means a bit more CPU—it probably won't noticeably affect responsiveness or battery drain, but you'd want to test that. And, more importantly, it will definitely make your code more complicated.
Obviously, if it's appropriate for your images, you could also do things like using non-Retina images (which will cut memory by 75%) or dropping color depth from RGBA-8 to ARGB-1555 (50%), but most images don't look as good that way (which is why we have high-color Retina displays).
I'm trying to optimize an iOS application which contains a lot of images and code. I have reduced the size of images with some programs but using instruments reveals that the application is still taking among 70-90mb of cache memory.
I have read that loading the resources(images) by demand and discard them when are not longer needed would be a good solution. How can i do it?
I have also a question:
When we use:
UIImage *aux = [UIImage imagenamed:#"image.png"];
and after we write aux=nil;
the image is discarded from cache?
Are only some of those images visible at a time? Write a system that loads only those images currently visible (and perhaps some that you application thinks might become visible soon). When you get a memory warning from the system, look for some images you've loaded in the past that haven't been visible for a while and release them.
To answer your second question, yes, setting a reference to nil will release it IF you are using ARC (Automatic Reference Counting), and if the reference you set to nil is the only reference to that object. All references to an object must go away before it will be released.
I would look at some of the solutions available, such as Path's FastImageCache, and see if they meet your needs. FastImageCache stores uncompressed images on disk in a format similar to Sprite Sheets (used by 2D games) so they can be loaded quickly when needed. The emphasis here is on improving scrolling performance, so if that's not an issue for you, this might not be the right tool for the job.
You might also look at this thread, although this is aimed at caching web images.
You might also take a look at The Tumblr Image Cache
Hi I have truble with allocated memory, because I noticed in Instruments a lot of Heap Growth, so I designed a test app.
Test app contained two ViewControllers and each have one button.
First ViewController was linked thru Segue Modal to SecondViewController (and it has NO code at all - beside auto-generated).
Second ViewController has only function
-(IBAction)back:(id)sender{
[self dismissModalViewControllerAnimated:YES];
}
so I could flip throw views.
When I test it whit Instrument I noticed heap growth after I go to second view and back.
How is that posible? What am I missing?
The size of the heap is not the app memory usage.
When your app is alive, the kernel will have to allocate memory for you.
Modern systems uses virtual memory. Basically, they map physical addresses to virtual addresses, that your process will access.
This mapping is handled by the kernel, and it needs memory for it.
If you request 1MB of memory, it will have to allocate memory to keep track of the physical pages allocated, by increasing the size of your adress space.
If you free all memory, the kernel will usually keep the memory used for the mapping, and re-use it for the next allocations, avoiding the need to reallocate space for it.
This is why the heap size doesn't change. But it does not indicate your application's memory usage at all.
If using Instruments, look at the VM Tracker tool for this.
In its simplest form, my app displays 10 UIImageViews, each containing an image. Even with all UIImageViews containing images, my app uses a small enough memory footprint. However, there is a button to clear all the UIImageViews by setting all their images to nil. The problem is, when checking Memory Monitor in Instruments, the memory held by the UIImageViews is NOT going away. This doesn't appear in the Allocations instrument, confirming the remaining memory footprint is not an object, but instead graphics-based memory. If I resize the images to something smaller or larger, the memory remaining is also smaller or larger, respectively.
Why is the image data sticking around after the UIImageView's image has been set to nil?
I believe UIKit keeps a cache of images for reuse. UIImageView might be releasing the object, but a copy is kept around for performance reasons.
These images, though, should be released on receiving a memory warning. If they're not, there's two places I'd check:
Make sure the UIImageView is being dealloc'd. Use Allocations Instrument to profile your app and do whatever you need to do in the program to load those images. Then unload the images and do a search for UIImageView. As long as you're sure your program should have released all of them, if you find any in the search you know something is wrong.
I'd also check any places the image was created, for example: UIImage = [UIImage imageName:#"Foo.jpg"]; Make sure these are also being released. You can use allocations to find UIImage classes, but it'll be harder to weed out the ones that should/should not be there.
Run the static analyzer: In Xcode 4 it's under Products -> Analyze. This is a great tool for finding logic errors, over/under release (if you not using ARC) etc.
Until actual UIImageViews are themselves released, their memory will remain allocated. Additionally, if you're using convenience methods on UIImage to obtain your images, eg:
UIImage *myImage = [UIImage imageNamed:#"myImage"];
Note that your image may cached behind-the-scenes by iOS, and so even if the image is being released by you, the memory footprint may still reflect the presence of the image in memory (eventually iOS will release it, so this shouldn't adversely impact your resource consumption).