My iphone application have a lot of high resolution images (eg: 2898 × 779 pixels dimension) and the whole project folder is only 17mb in size but if i run the application and when the first view is loaded the real memory and dirty memory showing in the VM Tracker in Instruments is more than 62mb.Can anyone help me to avoid this?Any suggestions will be thankful.
Images once loaded into memory lose (most of?) their compression. So unfortunately, the images may not look big when on disk (bundled in the app) but they can be a lot bigger once loaded into your app.
one 2898x779 image in ram will effectively use 2898x779x4 bytes = ~9mb, compare that with how big your image is on disk and you should see the difference.
so to actually answer your question, either downsize your images (because your devices screen is probably not that big, unless retina ipad or something) or use a CATiledLayer which will only load up parts of the image that are visible on the screen, and not the whole image.
5 tips to reduce memory issues in iOS apps
1. Use virtual memory
iOS doesn’t use swap file but it does support virtual memory. If an app keeps a lot of data in memory for random access you want to organize it as a mapfile rather then loading it to RAM with
malloc()
. An easiest way to do that is to call
NSData initWithContentsOfMappedFile:
2. Avoid stacking autoreleased objects
When you instantiate objects like NSString with no explicit allocation they live until the release of your autorelease pool – typically until your app quits. Extensive usage of such techniques may lead to a lot of garbage in RAM. Use
NSString initWithContentsOfFile:
so you can later release it instead of
NSString stringWithContentsOfFile:
. The same rule applies to
UIImage imageNamed:
– this is not recommended to use for image loading.
3. Handle memory warnings
Unload unnecessary resources when handling memory warning. Even if you can’t unload any of your stuff call
[super didReceiveMemoryWarning]
in all your UIViewControllers. That will by default free some resources like UI controls on non-front views. Failing to handle this event may make iOS decide that your app deserves killing.
4. Consider limited usage of animated view transitions
Animations like flip transition are noticed to cause RAM usage spikes when executed. This feature is very neat and should be used in many cases but it may trigger memory warnings in a heavily loaded multitasking environment. In particular we strongly recommend to avoid animating OpenGL views.
5. Test your memory footprint on device
Use instruments to test. The most useful tools are Allocations, Leaks and Activity Monitor. Testing on simulator is not relevant in most cases since its memory footprint tends to be completely different. Once you test you can figure out how much RAM each part of your app uses, where are the bottlenecks and how you can optimize.
From http://surgeworks.com/
Related
I have a universal app that is essentially a list of articles with images and text, and menu under the left side of the app. I have google analytics in, as well as parse's framework.
The only difference between the app on the iPad and iPhone is that the side menu is always visible on the ipad, and a few interface objects are moved around. (different cell layout for the list--same content, though).
The images are loaded asynchronously using a set of classes that I wrote to download/save in an NSCache object and on the disk using a NSOperationQueue. (disk cache is wiped when the user leaves the app). The NSCache is set to max out at roughly 10 mb. (assuming image size is image hight*image width * 4 bytes per image). (code here is identical for both, so it shouldn't be the culprit, but it is a large chunk of the apps memory use).
I was having some trouble with memory warnings/crashing on an older iphone4 running iOS 5.0, so I ran the app with the Activity Monitor Instrument, and noticed something very odd:
On the iPad (an iPad 2 running iOS 5.1) the app launched, loaded the images that were visible immediately, and was using about 16mb of memory.
On the iPhone4 it launched, loaded the visible images and was using about 35mb of memory--way more than I would expect.
In order to check if it was an OS memory issue, I also ran the app on an iPhone5 running iOS6 and it used about the same amount as the iPhone 4.
I checked my media and the storyboard files to see if anything was different at all, and I could not find anything that could change the memory usage in any significant way.
Is there any way to reduce the memory use of the app on the iphone? I can think of no reason it would use so much memory.
Very difficult to see.. as one person stated pay attention that retina devices will use more memory according to the source, if in the bundle you set #2x images it will load them, and they use more memory.
Have tried to profile the Virtual memory using allocations?
Using memory is usually fine even if it fires a memory warning, the problem is how you respond to it, when it comes does it free enough memory? try with the simulator to simulate a memory warning. Pay attention that sim uses more memory than device.
One other point is that since ARC is difficult to create leaks, but it's easier to create retain cycle and abandoned memory. A correct object life cycle should end with object deallocation.
You say that you use NSCache and load images from the net async, I've got 3 suggestion for you :
Do you know the original image size on the source? maybe on the iPad source images are smaller than on iPhone. A correct approach after you download an image will be resize it according to the really needed size (I'm mean redrawing non just stretching) you ca achieve that with Quartz or using ImageIO
I never understood the behaviour of NSCache after memory warning, Apple says that it will flush the memory but after some test on iOS4 (I don't know now) I don't agree. I've created my own subclass that observe for memory warning and flushes memory
Are you totally sure that you are getting back image from the cache ?
I am updating app to make it compatible with IOS 6, getting memory warning. live bytes in instrument shows low usage (2.3 MB). In VM tracker dirty size gets around 50%. in VM Tracker type = CG Image -> dirty size increases to 100%. My app requires users to take pictures but i am not using any core graphics objects. is there a way to release CG Image dirty memory ? thank you for taking time and reviewing my request.
My app using ARC starting leaking memory very badly on iOS6 whilst it ran perfectly on iOS5. When I say "leaking", I actually mean allocating memory and then not releasing the memory properly when I removed objects from mutable arrays, causing the app's memory usage to increase dramatically.
After lots of frustration, I've managed to fix it by setting up an #autoreleasepool { ... } around the offending section.
My suspicion is that iOS6 is threading my app differently compared with iOS5, as there used to be an #autorelease pool covering that process.
I suggest you try that solution as it is very quick to implement.
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.
For the last few weeks I've been tearing my hair out trying to get a tiling mechanism working on an iPhone. I need to scale and crop images of about 150mb so that they can be saved as tiles that will be requested by a scroll view, allowing the user to see the image in high resolution.
The problem is that these images are really pushing the bounds of what an iPhone can handle. It seems quite easy to scale these huge images down to 1000 or so across and do that tiling, but for large zoom levels I need to scale it mid-way, say 4000 across and that's too big. So I hit upon the idea of making medium sized blocks from the full sized image and tiling each of those and the medium zoom.
By creating an autoreleasepool around the inner loops, and draining it after each cycle I can mostly keep the memory under control but sometimes, and to me it seems random, memory is getting leaked, or at least not drained. I'm doing all this on a secondary thread and when it gets back to the first function in that thread I release the thread's own autoreleasepool and only then do the last memory artifacts get cleared. It doesn't seem to bother the simulator but the iPhone is much less forgiving and it crashes before it can complete the whole tiling process. The cropping code I am using is from Hive05
http://www.hive05.com/2008/11/crop-an-image-using-the-iphone-sdk/
Has anyone else had to deal with such massive images before? Is pre-generating tiles the best way to go? Any suggestions on why some loops would increase the memory and some not, or how to force every auto-released thing to clear on the inner pool instead of waiting for the outer pool?
Thanks for reading this far.
for got to add, these images are TIFs, so perhaps a direct reading of the bitmap info would be better than scaling and cropping the entire thing
First of all, I have serious doubts that an 150 MB image would fit in the device's memory, even if we're talking about a 3GS. That one has about 128 MB available memory for 3rd party apps maximum. See the device console messages and look for memory warnings, I guess you'll see that before crashing, the app emits them when trying to load your image. Reading the bitmap info in chunks would seem more sensible, as you'll be managing smaller sections at a time. I don't think Cocoa has a random-access file API, so you'll have to resort to a C function.
I've managed to write the loops that cycle through tiles of 1024x1024 and my iPhone 3G is able to finish the processing. It takes over 30 minutes though so it isn't great but that's what you get for working with 150mb TIF on a cellphone.
To keep the memory usage low I had to drain the AutoReleasepools after each iteration. Apple Tech Support pointed out that since the iPhone is a reference-counted environment rather than a garbage collected environment it is better to create a new AutoReleasePool at the start of each inner loop and drain it at the end of each loop than to create it before any loops start, drain it many times and then release it after the loops are done. Until I made that change my app would crash an iPhone but run fine on the simulator.
I'm working on an iPhone game that uses an MKMapView as the playfield. After only a couple of minutes of play the app inevitably starts to get sluggish and eventually crashes due to low memory. After digging around the culprit seems to be that the map view constantly demands more memory. The game requires a lot of zooming and panning of the map so I can only assume that the map's cache of tiles just keeps growing until it runs out of memory. Is there any way to force the map view to flush it's cache of tiles or contain it's memory consumption?
* NOTE: This answer is only relevant to iOS 4.1 and lower. The problems described in this answer were mostly fixed in iOS 4.2 *
I've been doing some digging on this as my app uses both the map and also has other features that demand high RAM.
I haven't found an answer, but a workaround. MKMapView's memory demands escalate exponentially as you zoom closer in to an area, and pan around within that zoomed in area.
There are two levels of MKMapView tile cache. One manifests itself as a Malloc ~196kb in Instruments, the other is NSData (store) of varying sizes.
The Malloc appears to be the active in-use tiles, and there is a hard cap on how many can be allocated. In my app that number is 16, not sure if its based on UIView size or not. These allocations seem to be stringently managed, and it responds to memory warnings.
Anyway, at a certain zoom level, say, continent level (enough to fit most of North America in an iPad screen), given the size of the tiles, if never really has to get to that second level of caching (NSData (Store)) in order to complete the map. Everything is crisp and clean. If I load in a ton of external images into active memory, the tiles prune themselves. Awesome!
The problem comes when it hits that second level of caching. This happens when you zoom in, and suddenly instead of 16 tiles to show the entire planat, it needs 16 tiles just to show off Los Angelas, and as you pan around instead of just dumping those old tiles it puts them into the NSData (store) allocations where they seem to never get freed.
This NSData (store) is the NSURLConnectionCache which exists by default only in memory. You can't access this cache to limit it, because it's not the default shared cache (already tried it).
So this is where I get stuck.
The unsatisfying answer is that if you disable map zooming and fix it at a reasonably broad zoom level, you can avoid this problem completely, but obviously some apps need this... and that's as far as I got.
I filed a support ticket with Apple to see if they can divulge any way to limit this ridiculous cache for the map (which by the way I was able to casually crank up to 50+ megs of RAM allocated in active memory).
Hope this helps.
edit
The next iOS release appears to have solved this limitless cache issue. MKMapView now aggressively prunes its cached tile data. REJOICE!
Are you setting the reuse identifier on your annotation views? (This means the system can detach those views and only keep a small number of views in memory at once. It also increases scrolling performance, because scrolling will reuse the detached views.)
Use this method to get an annotation view to be reused:
- (MKAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier
If you create an app with just the mapkit and a view size of 768x1024 (ipad size), the app can easily consume over 30+ MB of "Live Bytes" as reported by Instruments Allocations program. This was noticed running on the iPad iOS v3.2.2 (the latest version until next weeks supposed 4.2 release). From my research it seems that this amount of memory is a lot for a single app, where most developers report receiving a level 1 memory warning around 15-25 MB and crashes soon after that level.