Reduce memory usage for universal app on the iPhone - iphone

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 ?

Related

How to reduce real memory consumption ios

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/

Memory warning IOS 6 App Dev with low live bytes in instrument

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.

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 :)

Crash during Quartz operations on large images

I have an app that can import images. My app doesn't need large images, so if I see an image larger than 512 pixels on a side, I resize it.
I'm using some image resizing functions that I borrowed from:
http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way
The resizing functions work really well most of the time, but I have some large photos in my library that are 5616x3744. When I try to resize this image, it sometimes causes a crash while executing CGContextDrawImage() (about half the time it crashes, although once I was able to process about 20 images before it crashed). It is not consistent about which images it crashes on yet.
I haven't tried this in the simulator yet, but have been running on my iPad in develop mode while connected to the debugger. When the app crashes, it exits right out of the debugger and returns with signal "0".
I was wondering if there might be a memory issue, but when I run it with the allocations instrument, it doesn't go past about 44meg before crashing, and my app gets no memory warnings.
Is the resize operation just allocating a HUGE amount of memory that causes an out of memory crash without getting any kind of warning first?
I guess I could restrict my app to smaller images, but I would like to know why the crash is happening to make sure that it isn't something random that could bite me later.
Any help is greatly appreciated!
Thanks,
Ron
I've done a bit more debugging and I think what is happening is that the OS is killing my App for allocating too much memory. Since it is done in a single operation, the OS doesn't get a chance to notify my app about running out of memory, and just kills the app. Kind of sad that an iPad can't even resize a single 20 megapixel photo without being killed. Hopefully the iPad 3 will have at least 1gig of memory! My iPhone4 will do 70 megapixel photos without a problem.

Clear MKMapView's cache of tiles?

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.