[Xperia SP General] mrhnet:
Android RAM Management

What's this thread about?

This is a brief account of some useful aspects of android memory management and what could be done to make it better or to suit our needs. This is arranged in two parts; A) RAM Management Lesson. B) RAM Management Tips. Whoever is familiar with the Android RAM management concepts can skip to the second part (2nd post). [highlight]Please read and understand carefully before applying anything to the phone. I'm not responsible for any unwanted effects thereby. Credits belong to respective authors of any MOD/APP discussed here.[/highlight]

A) RAM Management Lesson

Android uses a different way of handling processes. Instead of killing every process after its activity ended, processes are kept until the system needs more memory. The idea is to give speed improvements if you start that activity again. But how/when does Android kill a process if it needs more memory and and which process to kill first?

This is managed by the LMK (Low Memory Killer) driver of Android. You may already know that every app/process in Android is assigned an oom_adj value, which indicates the likelihood of it being killed when an out of memory (OOM) situation occurs. More higher it's value, the higher likelihood of it getting killed. Valid range is -17 to +15. (if in the -17 range means it won't get killed). According to that, there are six groups (OOM groups), into which apps/processes are categorised:

1. Foreground app

2. Visible app

3. Secondary server

4. Hidden app

5. Content provider

6. Empty app

Basically these could be described as..

These groups are defined by oom_adj value limits, and apps would fall into one of those groups according to the oom_adj value assigned to that particular app. "Foreground apps" usually have an oom_adj value of 0 or less (so they are the least killable; i.e High priority). "Empty apps" have a higher oom_adj (they are killed early; i.e Low priority). Also, oom_adj value changes according to the state of the user app; it's 0 when the app is active in the foreground and assigned a higher value when the app goes to the background.

Why their "killability" differ? Apps belonging to these different groups (that have different oom_adj's), start to get killed at different levels of free RAM. These triggering RAM limits are defined by the LMK minfree values.

Above 6 categories correspond with 6 RAM limits which are set in the LMK minfree.

Eg: Stock Android 4.3 in our SP comes with the minfree values of 58,68,78,88,98,118. (these are in MB; see below how to check it). Practically what it means is, Empty apps will get killed when ram goes below 118mb, Content providers when it goes below 98mb, Hidden apps when it goes below 88mb and so on.. lastly starts killing Foreground apps when ram goes below 58mb. You may notice that this last value (58mb) is not desirable when using memory intensive apps like heavy games. The app might shutdown while we interact with it. It won't be a surprise if RealRacing3 would shutdown in the middle of a race with these minfree settings!

[Highlight]Notes:[/highlight]

1. In our SP (and newer kernels), oom_[highlight]score[/highlight]_adj is used instead of old oom_adj. (oom_score_adj valid range is -1000 to 1000). But oom_adj is also maintained for compatibility I think.

2. It is said that there are many OOM process categories that are assigned different oom_adj priorities by the ActivityManagerService, but eventually all of those would be considered under above six slots/groups (according to oom_limits), for the purpose of killing by the LMK minfree triggers. Therefore, those six are the importatnt ones for normal users like us.

[highlight]Now, to the practically important part...[/highlight]

# We can check the minfree values (also change them) and see the OOM groupings of apps/processes with this

Memory Manager app

easily.

a) LMK Minfrees:................... ......................................b) OOM groupings:

....

If we click on an app in the list and select 'more info', we can see it's oom_adj value. In my case, System UI has -12 (foreground), Home Launcher has 1 (visible group) etc..

# We can check these

manually in a terminal

too..

a) LMK Minfrees:

Give the following command (without quotes) in a terminal emulator or adb shell: "cat /sys/module/lowmemorykiller/parameters/minfree"

$ cat /sys/module/lowmemorykiller/parameters/minfree
[b]15000,17532,20065,22598,25131,30263[/b]

** These are in pages; 1 page=4K. Therefore, converting these in to MB results in.. 58,68,78,88,98,118. (e.g: 15000 x 4 /1024 = 58,5938)

b) OOM_adj value of an app:

*This is not much useful. But nice to know where to get these values from.

E.g. take home launcher. Find out it's PID (process ID) like this.. (command with output posted)

$ ps |grep [b]home[/b]
u0_a26 1653 721 471408 78076 ffffffff 00000000 S com.sonyericsson.home

It's pid is 1653. To see it's oom_adj value..

$ cat /proc/[b]1653[/b]/oom_adj
1

It's 1 (foreground). You might get 6 (hidden). So, your home is easily killed than my home :p. See below why..

At the same time we can see the new oom_score_adj..

$ cat /proc/[b]1653[/b]/oom_score_adj
58

* To convert old oom_adj value to newer oom_score_adj..

oom_score_adj = (oom_adj x 1000)/17 (truncate the decimals). So, (1x1000)/17=58.823

*There's another value (0-1000) of oom_score (cat /proc/1653/oom_score), which is THE actual indicator of how likely a process will get killed. It changes according to the tunable oom_score_adj and other factors..? something like that.. forget it! :D

[highlight]## The above mechanism could also be described according to what is mentioned in kernel source files[/highlight], as below. Can skip if it's boring :D..

It's from 'drivers/misc/lowmemorykiller.c' of kernel sources (4.3; .266)

If we take our phone values, "cat /sys/module/lowmemorykiller/parameters/adj" command returns: "0,58,117,235,529,1000". These are in (new) oom_score_adj values. If we convert them to (old) oom_adj values, these become "0,1,2,4,9,15". (eg:117x17/1000=1.989=2; The last value becomes 17, but oom_adj range ends with 15, so we take 15). Now, with our minfrees of 58,68,78,88,98,118, what it means practically is to kill processes with a oom_adj value of 0 or higher when the free memory drops below 58mb and kill processes with a oom_adj value of 1 or higher when the free memory drops below 68mb and so on... Therefore, it's clear that the adj values "0,1,2,4,9,15" (or score_adj values "0,58,117,235,529,1000") define the limits of each of 6 OOM slot described above.

Another point to note is what mentioned above in the kernel source file "..driver considers memory used for caches to be free..", which is described below.

[highlight]What is "Free RAM"?[/highlight]

What's reported in many apps as "free ram" is actually not free/empty. Linux/Android always tries to utilise the whole ram in some way, so the ram is not wasted. Ram which is not used by active apps, is used for caching apps and for some buffers. These caches and buffers can release memory for apps when needed. We can see the ram usage in detail with this command.. "cat /proc/meminfo" [giving "watch cat /proc/meminfo" would refresh the output every 2 seconds].

$ cat /proc/meminfo
MemTotal: 859764 kB
[B]MemFree: 26380 kB
Buffers: 2008 kB
Cached: 136600 kB[/b]
SwapCached: 0 kB
Active: 557312 kB
Inactive: 70520 kB
...blah.. ..blah...
....

Reported "free ram" was ~150mb when this was taken. Out of that, most (135mb) is already cached. ["Free RAM"=MemFree+Cached]. Actual free is very little. So, increasing "free ram" makes the phone much snappier because most of that "free" part of the RAM is used for caching things.

-->> RAM Management Tips