Responding to RAM availability in iOS
Asked Answered
B

4

9

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:

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

  2. PVRTC isn't an option. The textures contain data to be used by fragment shaders and must be stored in a lossless format.

Blighter answered 7/11, 2011 at 4:9 Comment(1)
Note that you can get both total ram and free ram stats as detailed in this thread free memory on iOS. Also, I tested the code on my iPhone 4 and it works well!Holocaust
P
11

To get the total (maximum) physical RAM of the device use [NSProcessInfo processInfo].physicalMemory.

See Documentation.

Pesky answered 2/10, 2013 at 15:46 Comment(0)
B
7

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.

Blighter answered 9/11, 2011 at 21:55 Comment(4)
Did you ever wind up getting this approved in an App Store app?Unlike
@Nate: Yes. Your World loads a 96-megapixel earth on devices with more than 384 MB; otherwise, it falls back to a 24-megapixel version. There's nothing special about the number; it's just half way between the devices that can, and those that can't.Blighter
Just use [NSProcessInfo processInfo].physicalMemoryPesky
+1 @Steve. Why on earth did no one point this out when I first asked the question? If you add this as an answer, I'll switch the green tick over to it.Blighter
S
2

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

Staircase answered 9/11, 2011 at 10:39 Comment(3)
Thank you for the detailed response. I can't accept this, because it doesn't answer the core question of how to detect RAM instead of using feature detection (Or are you implying that that's impossible or not worth pursuing?), but +1 for pointing out scale > 1.0 to detect the iPhone 4. I hadn't thought of that.Blighter
The only way you can try and detect memory without jailbreaking is by trying to fill it all and measuring how much you got. Also since memory is shared with all the other apps wich might be running (sytems ones, like mail, etc) even knowing the amount of physical memory isn't worth much. That's why I said to forget that route, it's not the solid ground you are looking for.Staircase
Your wording was ambiguous as to whether I shouldn't think of video memory as separate, or give up on measuring RAM. I don't care about other running apps; empirically, devices with 256 MB always crash, while those with 512 MB never do. Also, your proposed test fails with the latest iPod Touch — retina & 256 MB — underscoring my fears about the fragility of model detection. Incidentally, hunting for a solution to the iPod Touch problem led me to a possible answer, which I'll post separately.Blighter
P
0

As far as I know the 3 most important things one can do is -

  1. implement - (void)didReceiveMemoryWarning and respond when iOS sends warnings 1 & 2.
  2. Profile code in Instruments trying to find leaks & better mem optimum ways of implementation.
  3. Detect device types & maybe use that info.
  4. 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

Piapiacenza answered 7/11, 2011 at 4:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.