9

My issue:

I'm processing streams of images in my app. Some of the images can be really big. So I need a way to tell whether I can process it at all with the remaining memory I have before I process an image. But how can I know how much remaining memory I can use?

My research results:

  1. I can know the total memory and user memory with this UIDevice extension.
  2. I can know the virtual, resident, wired, active, inactive, and free memory by this.

My logs:

2013-12-13 11:15:05.966 Total Memory: 505 MB    User Memory: 434.3 MB
2013-12-13 11:15:05.967 Virtual: 348.7 MB   Resident: 6.3 MB    Free: 254.1 MB  Inactive: 35 MB Active: 70.7 MB Wired: 70.6 MB
2013-12-13 11:15:57.742 Virtual: 530.2 MB   Resident: 95.2 MB   Free: 160.6 MB  Inactive: 45 MB Active: 74.1 MB Wired: 72 MB
2013-12-13 11:16:41.320 Virtual: 569.2 MB   Resident: 88 MB Free: 121 MB    Inactive: 46.4 MB   Active: 71.8 MB Wired: 76.3 MB
2013-12-13 11:16:46.254 Virtual: 612.9 MB   Resident: 88.7 MB   Free: 50.2 MB   Inactive: 33 MB Active: 64.2 MB Wired: 117.7 MB
2013-12-13 11:16:49.536 Virtual: 525.6 MB   Resident: 89.9 MB   Free: 3.6 MB    Inactive: 33.8 MB   Active: 154.3 MB    Wired: 71.7 MB
2013-12-13 11:16:50.854 Virtual: 568.9 MB   Resident: 90.1 MB   Free: 139.5 MB  Inactive: 35 MB Active: 64.1 MB Wired: 71.2 MB
2013-12-13 11:16:56.358 Virtual: 613.8 MB   Resident: 92.6 MB   Free: 51.3 MB   Inactive: 35.1 MB   Active: 107.1 MB    Wired: 71.5 MB
2013-12-13 11:17:05.034 Virtual: 658.4 MB   Resident: 83.9 MB   Free: 48 MB Inactive: 30.5 MB   Active: 62.4 MB Wired: 70.1 MB
2013-12-13 11:17:15.196 Virtual: 587.4 MB   Resident: 143.1 MB  Free: 194 MB    Inactive: 6.2 MB    Active: 15.1 MB Wired: 69.5 MB
2013-12-13 11:17:18.483 Virtual: 629.3 MB   Resident: 145.2 MB  Free: 97.2 MB   Inactive: 6.3 MB    Active: 47.3 MB Wired: 92.3 MB
2013-12-13 11:17:21.098 Virtual: 675.5 MB   Resident: 145.2 MB  Free: 52.7 MB   Inactive: 24.2 MB   Active: 51.6 MB Wired: 69.3 MB
2013-12-13 11:17:22.133 Received memory warning.
2013-12-13 11:17:22.187 Virtual: 711.3 MB   Resident: 172.1 MB  Free: 36.1 MB   Inactive: 20.4 MB   Active: 1.8 MB  Wired: 114.3 MB
2013-12-13 11:17:22.477 Received memory warning.
2013-12-13 11:17:22.480 Virtual: 568.1 MB   Resident: 124.7 MB  Free: 194.6 MB  Inactive: 20.9 MB   Active: 3.3 MB  Wired: 112.4 MB
2013-12-13 11:17:22.571 Virtual: 522.6 MB   Resident: 36.2 MB   Free: 282.4 MB  Inactive: 20.9 MB   Active: 3.9 MB  Wired: 66.8 MB

My questions:

  1. What does the amount of virtual memory mean on iOS? As I know, iOS does not have swap so there is not hard disk involved. But I found it CAN and most of the time DOES exceed user memory and even total memory.
  2. What's the relationship between resident memory and {wired, active, inactive} memories? I know the relationships among the latter group.
  3. Why is the sum of {wired, active, inactive, free} memory inconsistent? What's the relations between this sum and total memory or user memory or virtual memory?
  4. How to calculate the amount of remaining memory that I can use in my app?

For the last question above, I tried using only free memory. I'm sure it is not right since most of the time free memory is very little and what I can use in fact can easily exceed that without any issues. I also tried (free memory + inactive memory). Still seems not quite right since I can use more than that without issues in my experiments. One difficulty involved here is that when my app is active and needs more memory the system can kill other inactive apps to spare more memory to my app. I need to take this later-spared amount into account when calculating the remaining memory that I can use.

Community
  • 1
  • 1
an0
  • 17,191
  • 12
  • 86
  • 136
  • No, you don't need this. Instead of trying to figure out how much free memory there is, just attempt allocating as much as needed, then handle errors. –  Dec 13 '13 at 17:45
  • 1
    @H2CO3 I can't. Allocating too much will just crash my app. – an0 Dec 13 '13 at 17:47
  • Allocating "too much" memory can't quite be done with modern (or any?) OSes. You will get an error (null pointer returned from `malloc()`, etc.) if you attempt to do so. –  Dec 13 '13 at 17:52
  • To be accurate, I don't alloc myself. Some framework functions I use do the alloc so I don't have direct control though I can estimate how much memory will be needed. – an0 Dec 13 '13 at 18:07
  • @H2CO3 see the link in my answer. The OS is going to terminate your app long before malloc returns NULL. – Ivan Genchev Dec 13 '13 at 18:16
  • @IvanGenchev Thanks for the link. However, that's only true when you don't even attempt to use the memory pointed to by the returned pointer. (This technique is called "overcommitting" AFAIK, you can do a quick search on SO and you'll see numerous questions and answers describing its behavior.) –  Dec 13 '13 at 18:23
  • @an0 In short, you can't know, exactly, how much memory is available to your app. Not remotely. And the number can change at any time (user receives a push notification, phone call, and/or some background process consumes resources). You really need to focus on ensuring that your app uses memory as efficiently as possible and responds to low memory situations cleanly. – bbum Dec 13 '13 at 22:19
  • @bbum I'm already doing whatever I can. The problem is when a big image comes I need to process it and if the remaining memory is not enough to handle that it will crash my app. So I need to determine whether I can safely do the image processing before I start doing it. Any suggestion? – an0 Dec 14 '13 at 01:23

3 Answers3

3

Question 1:

You are confusing virtual memory with the concept of swapping. It's a common mistake.

Virtual memory is the total amount of address space that is mapped and accessible to your process rather than the amount of memory it directly uses.

This includes:

  • Private pages (e.g. those written by the process)
  • Shared pages
  • Virtual address space corresponding to mmaped files
  • IO address space of peripherals memory mapped into processes - GPU memory being the common one, but also sometimes serial busses such as Infiniband, Firewire and probably Thunderbolt

It's the third of these that accounts for the bulk of the address space usage as it includes the read-only portions of executing code, and in particular, shared libraries. The operating system will keep some of these resident in physical memory, but may jettison them when necessary (they can always be reloaded from disc as required).

Swapping is the process of writing the dirty pages belonging to a process to disc. There is no swapping in iOS. Instead iOS asks applications to reduce their memory consumption by deleting unused view controllers and flushing caches. If this doesn't solve the problem, it looks for processes to kill. Processes using lots of physical memory are prime candidates.

Question 2:

Wired memory is address space that must always be mapped to physical memory. Things that reside in wired memory are:

  • The operating system itself (some operating systems - such as the Windows NT Kernel - can actually swap parts of themselves out, but Darwin doesn't)
  • Private data used by the operating system
  • IO Buffers used for DMA
  • Any memory shared with the GPU.

I'm not quite sure of the distinction between active and inactive here, but in general, file-cache (e.g. mmaped pages) are always the first candidate for reallocation when there is pressure on memory. In this context, a free page is one the operating system is not using for anything. All decent modern operating systems will always use most of its free pages for file-cache. A page is generally only free because nothing yet has been cached in it.

Before you think that all of these pages are yours for the taking, remember that a lot of them are filled with application code. If that code is needed, it will be reloaded from disk.

Question 3:

The sum is inconsistent because of sharing of between processes. This is why shared libraries save memory. The Darwin kernel relies on a neat optimisation where child processes inherit memory mapped files from their parents. A top-level parent process - probably launchd mmaps a large number of common system libraries, thus ensuring child processes get them for free. This accounts for a large amount of virtual address space in each process, and explains why they are fairly similar at ~600MB.

Question 4:

You can't reliably. Your only option is to do it empirically. In other words, how much memory can you consume without your application causing performance of the rest of the system to suck, or getting terminated by the operating system for using too many resources. You can't even rely on the free pages being available to use more than short-term.

marko
  • 9,029
  • 4
  • 30
  • 46
0

I am not currently aware of any way to know how much memory is left to you.

However, iOS does give your app memory warnings to let you know that free memory is very tight. If your app gets one of these warnings, you should start freeing memory.

Community
  • 1
  • 1
BergQuester
  • 6,167
  • 27
  • 39
0

See the Memory Usage Performance Guidelines and in particular this:

When a low-memory condition is detected, the system delivers low-memory warnings to all running programs (including your application) and may terminate some background applications (if necessary) to ease memory pressure. If not enough memory is released—perhaps because your application is leaking or still consuming too much memory—the system may still terminate your application.

Basically you should free up some memory as soon as you receive a low-memory notification and you won't even care how much is the free memory on the system, otherwise the OS is going to terminate your application at some point.

Ivan Genchev
  • 2,746
  • 14
  • 25