Ideal memory usage amounts for iOS apps - ios

What ranges could be considered Low, Medium, and High in memory usage?
As my app becomes more complex, I notice this number getting higher. I've been trying to use this number as an indicator to how efficiently I'm coding but I've realized I have no bar to compare it with.
How to understand Memory Usage says 1024 Mb to an iPhone/iPad, but obviously all of this memory can't go to the app.

You could get(a pretty nice) overview from this SO question. It won't show you low-medium values, but if you know the limit you can adjust below limit.
If you are near the limits in some view - override didReceiveMemoryWarning and dispose resources accordingly.
My advise is to test always on device, as simulator need a lot memory just because of it's architecture and it's not relative to real devices.

Related

How do I determine which threads are taking up memory in my iOS app - information from Instruments is limited?

My application has many different components - an AR view, a separate SceneKit view, UI, and underlying algorithms which are ongoing.
I want to determine which area could be causing performance issues. Here's what Xcode gives me, under CPU:
These threads all appear to be re-sized so that they fill the height of their graph. So it's not useful to determine what's actually taking up resources.
And here's what Instruments gives me, under Time Profiler:
Here I can clearly see that some threads dominate, but it's impossible to identify any of these threads.

Xcode Memory Graph - showing increasing memory use - what exactly does it show?

When watching the debug graph in xcode 6 (and probably 5 too), when running my application the memory use continues to rise as I place more of a certain object on the screen and animate it's movement. It does not seem to decrease when I remove it. Once removed I believe there are no more references to them.
See screenshot:
http://i.stack.imgur.com/SnhbK.png
However when I use Instruments to try to identify what's going on, there's only around 12mb persisting, and Total Bytes continues to rise, as expected.
See screenshot:
http://i.stack.imgur.com/VBwce.png
Is this normal behaviour? What exactly is the graph in Xcode showing? Am I overlooking something?
In Instruments I have Allocation Lifespan set to All Allocations and Allocation Type set to All Heap and Anonymous VM for the screenshots above.
UPDATE
By running Instruments with Activity Monitor I was able to see that the "Real Memory" was increasing at the same rate as is displayed in Xcode. #Mark Szymczyk pointed out that OpenGL ES Texture memory allocations are not shown in the Allocations instrument.
By purging the texture cache with the following command in Cocos2D 3.1 at regular intervals, memory use consistently drops back down to around 18mb and begins increasing again as I add more sprites.
[[CCDirector sharedDirector] purgeCachedData];
Credits go to Mark Szymczyk for pointing me in this direction - thanks!
Looking at your screenshots, the Xcode graph is probably showing the equivalent of the Total Bytes column in your Instruments screenshot. When you remove an object, the persistent bytes will decrease, but the total bytes won't. That would explain why the memory use never goes down in the Xcode graph.
The Persistent Bytes column in Instruments is what you should be looking at to determine your app's memory usage.

App keep crashing due to memory pressure

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

Maximum (practical) Memory Use on iPod Touch 4G, iOS 5

We have a memory-intensive 3D app which is primarily targeted at iPad 2 and iPhone 4S, but it works on iPod Touch 4G and iPhone 3GS as well. We have found that the smaller memory footprint on the iPod Touch 4G, combined with the retina display, makes this platform more susceptible to out-of-memory errors. iOS5 also seems to have lowered the available memory somewhat.
It's relatively easy for us to lower the resolution of 3D models, based on the platform we're using, but we have to set that resolution before loading, and thus we cannot effectively lower it dynamically based on memory pressure warnings from the O/S.
We've tuned the memory usage based on trial and error, but we've found that devices that haven't been rebooted in a long time (e.g., months) have a lot less useable memory than devices which have been rebooted recently. (Even if you kill off all the running apps.)
I'm wondering what other iOS app developers use as their practical memory limit for iPod Touch 4G apps?
While keeping all the caveats that everyone is offering in mind, my personal general rule of thumb has been that in sensible weather you can expect to have around the following:
512MB device -> 200MB usable (iPhone 4-4S, iPad 2)
256MB device -> 100MB usable (iPhone 3GS, iPad, iPod Touch 3G-4G)
128MB device -> 50MB usable (iPhone 3G, iPod Touch 1G-2G)
And if you want to rigorously withstand insensible weather without otherwise making a point of being flexibly responsive with memory usage, you can halve those numbers, or even third them. But it will be fairly difficult to guarantee sterling reliability if you can't throw anything overboard when conditions become dire. It's more like a sliding scale of how much performance you're willing to throw away for how much reliability at that point.
In environment predictability terms, iOS is a lot more like the PC than a dedicated machine, for better and worse, with the added bonus of a drill sergeant for an OS.
Recently I found this awesome tool to find what is the maximum memory capacity of any iOS device. We can also find at which memory level we received the Low Memory warning.
here is the link: https://github.com/Split82/iOSMemoryBudgetTest
It's hard to give an actual number because of all the external allocations the OS does on your behalf in UIKit and OpenGL. I try to keep my own allocations to around 30MB, with 50MB sort of my top end. I've pushed it as high as 90MB, but I got jettisoned a lot at that level so it's probably a bad idea unless the task using all that memory is very brief.
If you need to hack around your current problem you could just detect the problematic devices up front and turn down your graphics engine's resolution at startup. You can get exact device info or you could check for display scaling (retina) combined with number of processor cores and amount of RAM to determine what quality level to use.
I've had great success reducing my memory usage by using mapped files in place of loading data into RAM and you may want to give that a try if you have any large data allocations.
Also watch out for views/controls leaking from UIKit as they consume a lot of memory and can lead to being jettisoned at seemingly random times. I had some code which leaked child views from several view controllers. Eventually those leaks would chew up my app, though my app's memory usage didn't reflect the problem directly.

Responding to RAM availability in iOS

I have a texture-heavy OpenGL game that I'd like to tune based on how much RAM the device has. The highest resolution textures I have work fine on an iPhone 4 or iPad2, but earlier devices crash in the middle of loading the textures. I have low-res versions of these textures, but I need to know when to use them.
My current tactic is to detect specific older devices (3GS has a low-res screen; iPad has no camera), then only load the hi-res textures for IPad2 and above and iPhone 4 and above — and I suppose I'll need to do something for the iPod touch. But I'd much rather use feature detection than hard-coding device models, since model detection is fragile against future changes to APIs and hardware.
Another possibility I'm considering is to load the hi-res textures first, then drop and replace them with lo-res the moment I get a low memory warning. However, I'm not sure I'll get the chance to response; I've noticed that the app often dies before any notification appears on the debug console.
How do I detect whether the device I'm running on has insufficient RAM to load hi-res versions of my textures?
Taking a step back, is there some other adaptive technique I can use that's specific to OpenGL texture memory?
Notes:
I've searched on and off SO for answers related to available RAM detection, but they all basically advise profiling memory usage and eliminating waste (minimising the lifetime of temporaries, and all that guff). I've done as much of that as I can, and there is no way I am going to squeeze the hi-res textures into the older devices.
PVRTC isn't an option. The textures contain data to be used by fragment shaders and must be stored in a lossless format.
To get the total (maximum) physical RAM of the device use [NSProcessInfo processInfo].physicalMemory.
See Documentation.
Total physical RAM is available via sysctl(), as documented in this blog post and implemented as a nice clean API here (see the implementation of totalMemory in the corresponding .m file).
I've lifted the blog's code for convenience and posterity:
#include <sys/sysctl.h>
size_t phys_mem()
{
int mib[] = { CTL_HW, HW_PHYSMEM };
size_t mem;
size_t len = sizeof(mem);
sysctl(mib, 2, &mem, &len, NULL, 0);
return mem;
}
I don't know if Apple will approve an app that uses sysctl() in this manner. It is documented, but only for Mac OS X.
The most important think you need to know for memory management in this case is wether to use High or low res textures. The simplest way I use is to check this
CGFloat scale = [[UIScreen mainScreen] scale];
if ((scale > 1.0) || (self.view.frame.size.width > 320)) {
highRes = TRUE;
}
This works for all devices so far and should be future proof, newer devices will use the high res.
You might also calculate right there the aspect ratio (helps later on ipad vs iphone)
aspect = self.view.frame.size.width/self.view.frame.size.width
Don't load highres first it kills your apps load time, on my 3G most of my startup is spent loading (even the low res) textures, just test for this right at the beginning and don't touch the highres stuff.
On older devices the program will die without warning due to big textures, may have something to do with de debugger not being able to trap the video memory consumption and dying itself.
For greater optimizations consider tinting you mipmaps to check the lowest texture size that's actually being used (only if your using 3D objects).
Forget the video RAM size issue, memory is actually shared, so you're competing for system memory, on older devices you had a MB limit for use, but it's still system memory.
About memory management, there are many ways to do it, the simplest should be mark the textures that are loaded, and textures that are needed, when a memory warning comes, dump the textures that are loaded but not needed...
As far as I know the 3 most important things one can do is -
implement - (void)didReceiveMemoryWarning and respond when iOS sends warnings 1 & 2.
Profile code in Instruments trying to find leaks & better mem optimum ways of implementation.
Detect device types & maybe use that info.
Use some form of texture compressions like PVRTC to save space.
I think you are doing most of them. The thing is one does not even know accurately how much RAM iOS devices has. Apple does not publish tech specs for iOS devices.
Also, it cannot be assumed that only after say 100mb of consumption you will get a mem warning. The warnings that iOS gives varies depending on the current state of the device & what other apps are running & how much mem they are consuming. So it gets tricky.
I can suggest 2 must read sections - Best Practices for Working with Texture Data and Tuning Your OpenGL ES Application

Resources