Search code examples
iosiphoneswiftipad

iOS difference between actual RAM and ProcessInfo.processInfo.physicalMemory stable?


I'm working on an App that needs to be tailored down on low memory devices. Available device memory would be given in swift by:

ProcessInfo.processInfo.physicalMemory

For instance:

  • iPhone SE gives 2009.5 MB (2048 MB RAM)
  • iPhone 5s gives 1000.0 MB (1024 MB RAM)
  • iPhone 6 gives 989.0 MB (1024 MB RAM)
  • iPhone 6+ gives 977.0 MB (1024 MB RAM)
  • iPhone 4s gives 504.95 MB (512 MB RAM)

From my understanding, the delta is allocated to the GPU and depends on the screen size.

Can I trust a given device to always give me the same physicalMemory amount?

(always 989.0 MB for an iPhone 6 for instance)


Solution

  • It looks like physicalMemory is the same as hw.physmem (or its macOS equivalent) from sysctl.

    The best description I could find is from a post comparing real/physical/user memory in FreeBSD:

    The amount of "usable" RAM for the OS.  This subtracts off
    any spaces reserved by boot ROMs / BIOSes / what-have-you, and
    in the case of (e.g.) FreeBSD-9 on amd64, the 1 TB direct-map
    limit (which you must take care of manually with the loader's
    hw.physmem setting).

    This is what "phys mem" should be and mostly is. If you boot a machine with 1.5 TB of RAM but the OS is limited to 1 TB, hw.physmem should be 1 TB minus a bit for the BIOS, etc.

    So, it's the actual memory on the device minus memory reserved by things that aren't iOS. Since we can't guarantee that Apple won't update any of these systems, we can't guarantee that the physical memory available for the app will be fixed. So I wouldn't hard code any of these magic numbers. You could look at retrieving the "real" memory size with a system call, but you could also just use memory buckets since you know physical will always be lower than but close to real memory:

    enum MemorySize {
        case low, medium, high
    }
    
    extension MemorySize {
        static var current: MemorySize {
            if ProcessInfo.processInfo.physicalMemory < 512 * 1024 * 1024 {
                return .low
            } else if ProcessInfo.processInfo.physicalMemory < 1024 * 1024 * 1024 {
                return .medium
            } else {
                return .high
            }
        }
    }
    
    ...
    
    if MemorySize.current == .low { /* Use low memory setup */ }