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). 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.
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:
// This is the process running the current foreground app. We'd really
// rather not kill it!
// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear.
// This is a process holding a secondary server -- killing it will not
// have much of an impact as far as the user is concerned.
// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
// This is a process with a content provider that does not have any clients
// attached to it. If it did have any clients, its adjustment would be the
// one for the highest-priority of those processes.
// This is a process without anything currently running in it. Definitely
// the first to go!
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!
1. In our SP (and newer kernels), oom_score_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.
Now, to the practically important part... # 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"
** 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 home
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/1653/oom_adj
It's 1 (foreground). You might get 6 (hidden). So, your home is easily killed than my home . See below why..
At the same time we can see the new oom_score_adj..
$ cat /proc/1653/oom_score_adj
* 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!
## The above mechanism could also be described according to what is mentioned in kernel source files, as below. Can skip if it's boring ..
It's from 'drivers/misc/lowmemorykiller.c' of kernel sources (4.3; .266)
* The lowmemorykiller driver lets user-space specify a set of memory thresholds
* where processes with a range of oom_score_adj values will get killed. Specify
* the minimum oom_score_adj values in
* /sys/module/lowmemorykiller/parameters/adj and the number of free pages in
* /sys/module/lowmemorykiller/parameters/minfree. Both files take a comma
* separated list of numbers in ascending order.
* For example, write "0,8" to /sys/module/lowmemorykiller/parameters/adj and
* "1024,4096" to /sys/module/lowmemorykiller/parameters/minfree to kill
* processes with a oom_score_adj value of 8 or higher when the free memory
* drops below 4096 pages and kill processes with a oom_score_adj value of 0 or
* higher when the free memory drops below 1024 pages.
* The driver considers memory used for caches to be free, but if a large
* percentage of the cached memory is locked this can be very inaccurate
* and processes may not get killed until the normal oom killer is triggered.
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.
What is "Free RAM"?
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].
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.
Following is an account of which i benefitted from, sharing for others who may not be aware of these. Your milage may vary... Desired "RAM Management" differs depending on whether expecting more multitasking or a snappy phone with lot of free RAM. Nowadays, phones with better specs generally won't show any lag even if tuned for multi-tasking , although "free RAM" stays little lower. I prefer towards more multi-tasking
1.Change the minfree values to suit your needs.(Need Root access).
LMK Minfree values can be changed on the fly. Use lower values if you want more multitasking. Higher values if need more "free ram" for gaming etc.. . I use 8,12,45,65,95,165 for more multitasking and for foreground apps to stay until ram becomes much lower. Asphalt8 never crashed with this! If we use values like 15,25,95,145,195,245 "free ram" would be more but background apps (e.g. Hidden apps) would shutdown earlier. However, make sure NOT to increase the first 2 slots too high, so that the Foreground and Visible apps would stay even if RAM goes lower.
How to set/change them:
a) You can set those values with the above Memory Manager app and press Apply. (and tick 'apply at boot' for those values to be applied at every boot).
** There are many preset values you can experiment with.
b) Or can do the manual way.. Give the following command in a terminal/ADB shell:
2.Use 'App Settings' xposed module to make any app "stay" in memory (make it "Resident"). (Need Root access)
It would definitely help multitasking by keeping the needed apps in the background without getting killed, even if RAM becomes low. It possibly works by reduces the app's oom_adj value. That's why you can see Opera Mini in the 'Foreground app' list in my screenshot above (1st post). It's oom_adj value is 0. You can do this for your home launcher and any app you wan't to stay un-killed in the background.
Caution: Making apps to stay in memory would make them stay without being killed, even when e.g. a heavy game is starving for RAM. Therefore, indiscriminate use of this option is not advised. I think it's better to..
(i) Apply only to the apps which have an 'Exit' button/menu, so we can shut it down when needed.
(ii) If no exit button, Add to the 'Greenify' list to be hibernated when the app is not needed. But it asks for confirmation before hibernating these kind of apps with 'High Priority' oom_adj status.
1. Get Xposed installer from here. Install it. Install the Xposed framework through it. Refer to the respective thread for more details.
2. Then download the 'App Settings' module through Xposed installer..
3. Open 'App Settings'.. App list will load.
4. Select the app you wan't to tweak.. It will lead to a page as seen in the screenshot above.
5. Select 'Resident' and save (upper right corner button). Can change any other setting if needed.
3.Use zeppelinrox's jar patcher tools to patch services.jar. (Need Root access).
It changes Home Launcher priority and many other LMK related tweaks. This is why you see my home launcher is under visible apps (oom_adj 1). No launcher redraws even after asphalt8! See the particular thread for details. In summary, patching services.jar results in (quoted from the thread):
- This will SuperCharge Your Home Launcher and ADJ/OOM Priorities! You pick launcher strength!
- This lets you run up to 70 hidden apps instead of the default 15 (RAM permitting) without breaking the lowmemorykiller!
- This tries to bypass the 30 minute service inactivity limit by increasing it to 24 hours.
** From ICS up, Android doesn't read ADJ values from build.prop or local.prop - they are hardcoded into services.jar! That is the reason for needing to patch services.jar to change OOM priorities. More details in the respective threads.
Get Jar patcher tools from the thread. I used 'Ultimatic_Jar_Patcher_Tools_RC7_TEST6_ALL_DEX_ALL _OSes_NO_FLASH.zip'. Extract it in the PC. Make sure ADB drivers installed.
How to run -=Ultimatic Jar Patcher Tools=-
1. Connect your Android to your PC with Android Debugging ENABLED and Mass Storage DISABLED so your device has access to your sdcard.
2. Windows: Run either the zip's *.bat or the attached *.exe
If running the exe, you can put a different ultimate jar power tools script version in the same folder and it will use that one otherwise it uses the embedded version!
If you have cygwin installed, you can even use the zip's *.sh file at the cygwin prompt.
Linux/Mac OSX: run the zip's *.sh file
Just be sure to read everything and answer Yes or No as is your preference.
Example: The script allows you to choose the level of your Launcher's Super Strength! (BulletProof, Die-Hard, or Hard To Kill)
** Always keep a cwm backup before attempting this; might not get it correct in the first attempt..
4. With the above jar patching, can use zeppelinrox's supercharger script. (Need Root access).
It can be used to change the minfrees and it re-groups the OOM categories. It also has tons of other cool tweaks. If we check "cat /sys/module/lowmemorykiller/parameters/adj" after applying the SuperCharger scripts to our phone, it returns.. "0,176,352,588,705,1000". Converting to oom_adj values (see 1st post) it becomes "0,3,6,10,12,15". Comparing with stock values (0,1,2,4,9,15), we can see that the above described six OOM slots are re-arranged, sort-of categorising more processes towards higher priority. Can test those settings by echoing those values (this won't survive reboot):
** Not advisable to meddle with this if no clear idea about what is being done. Use the SuperCharger script instead. Checkout the respective thread for more info.
[For me, this OOM regrouping made some task killings more difficult and it didn't relese RAM readily when needed for heavy games..(may not be same for others ). So I'm not using it at the moment. I'm setting up minfrees as described previously.]
1) Get the latest SuperCharger script from the thread.
2) Make sure requirements are met. Eg: Rooted, Busybox installed.
3) Run the script through 'Script Manager-Smanager' app (with root access granted).
4) Read the output of the screen and reply to the prompts accordingly. ** Keep a cwm backup before attempting this, just in case..
5.Override the "Hidden app limit" of Android.(Need Root access).
In addition to the LMK driver mechanism described above, this is another parameter that leads to killing of Hidden and Empty apps. Apps are killed when the number of those apps go beyond the specified limits. (Traditionally it was 15, so no more than 15 hidden apps would stay in the background even if there's plenty of RAM). There's a build.prop setting which can control this in our SP. (Btw, services.jar patching mentioned above makes that limit to 70). With the build.prop setting mentioned, we could make it to even 150 ! (This way, we can maximize multitasking and app killing is fully handed over to LMK minfrees, which we can control).
Add this line to end of build.prop file (in /system) and leave another blank line below that, and save the file. Then reboot. Tip:Build Prop Editor is an easy way to edit the build.prop. ** Always keep cwm backups before doing these kind of things.
How to test:
a) Install CatLog app (need root) [This is for reading Logcat]
b) Run it and enter "longer" (without quotes) in the filter bar. Might get a filtered output like this:
It means that the 24th Empty app had got killed, because of exceeding the hidden app limit. This is after services.jar patching making the Hidden app limit to 70. Before it was #17 if I remember correctly.
c) Check the same output after applying the build.prop setting. Should get a little increase. (When I made Hidden app limit to 100, output was #34th empty app gets killed. So, I wen't upto 150 until that kind of output disappeared ).
## Credits to @zeppelinrox for finding that build.prop setting. You can read what happened here in his thread.
In Android 4.2 the max hidden apps are divided into 2 parts (In AMS smali the value is stored in "mProcessLimit")
Part of it goes towards hidden apps.
Part of it goes towards empty apps.
So what happens is it gets the max apps limit (v2)
It gets multiplied by 2 so "v2" is doubled in value.
Now... that is divided by 3 and that value is assigned to empty apps (v13)
Finally, empty apps (v13) is subtracted from v2 to give you hidden apps (v17)
So by default, there are MORE empty apps than hidden apps!
2/3 are empty
1/3 are hidden
So your original config was probably...
max hidden apps = 25
empty apps = 17 (25x2/3)
hidden apps = 8 (25-17)
So normally (without jar patching), if the limit is 70 it would break down like this...
That's why my 24th Empty app was getting killed with app limit of 70. You might get a totally different value if this build.prop setting is applied without services.jar patching. Appreciate your feedback
** Please Note: I'm no dev. I wrote this according to what i understood by reading around in the net. I'd be more than glad if anyone points out any shortcomings/improvements. Thanks.
Many of us refer to 'Settings>Apps>Running' to see how much free RAM is available at a particular moment. Generally we believed that it shows the correct value. But, some observations makes that value doubtful. E.g: This value doesn't tally with /proc/meminfo values. Furthermore, 'Free RAM' indicated by other apps at times are totally different.
Hi @mrhnet: I got pinged by your mention of my username. Thank you for this valuable thread! It's so important for xda having people around which actually explain and give knowledge to others! This is how a community should work! Great work!
P.S.: Also thanks for giving me credit. That's not to be taken for granted. When I search the web for the unfortunate typo in my posting "on Android the current forefround application" I find a lot of resources which simply copied my words and often did not give any credit. So I appreciate this very much!
XDA Developers was founded by developers, for developers. It is now a valuable resource for people who want to make the most of their mobile devices, from customizing the look and feel to adding new functionality. Are you a developer?