Tl;dr
It's possible with root, you can tweak oom_adj
values to prevent apps from being killed, alternatively force the target app to stay in memory by "locking" it or change some related settings responsible for killing apps in low memory condition.
Background: Android RAM Management
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 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:
- Foreground app
- Visible app
- Secondary server
- Hidden app
- Content provider
- Empty app
Basically these could be described as:
FOREGROUND_APP
: This is the process running the current foreground
app. We'd really rather not kill it!
VISIBLE_APP
: This is a process only hosting activities that are
visible to the user, so we'd prefer they don't disappear.
SECONDARY_SERVER
: This is a process holding a secondary server --
killing it will not have much of an impact as far as the user is
concerned.
HIDDEN_APP
: This is a process only hosting activities that
are not visible, so it can be killed without any disruption.
CONTENT_PROVIDER
: 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.
EMPTY_APP
: 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 my
device comes with the minfree values of 48,60,72,84,96,120
. (these
are in MB).
Practically what it means is, Empty apps will get killed when ram goes below 120mb, Content providers when it goes below 96mb, Hidden apps when it goes below 84mb and so on.. lastly starts killing Foreground apps when ram goes below 48mb. (You may notice that this last value (48mb) is not desirable when using memory intensive apps like heavy games).
NB:
In newer kernel, 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 perhaps compatibility.
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 important ones for normal users.
- We can check the minfree values (also change them) and see the OOM
groupings of apps/processes with this Memory Manager app easily.
Not every device has the same OOM configuration.
Improving RAM Management
Nowadays there is much user friendly implementation of RAM management mechanism with UI in system settings (such as App optimisation in Battery settings, Protected apps in some ROMS e.g Huawei’s EMUI etc) and can have the same effect as described above:
Having said that we can now explore ways in which, RAM can be utilised without killing foreground applications too often. The target areas will include:
1.Adjusting minifree values to suit one’s needs
2.Locking apps in memory to prevent them from being killed
3.Overridding the hidden app limit of android
Adjusting minifree values
You can change the minfree values with memory manager and tap apply. (Additionally there is an option “apply at boot” and tick to preserve settings across boots). Several apps can achieve this e.g Memory manager, Minfree manager etc
Alternatively use terminal/adb using pages:
#!/system/bin/sh echo “values” > /sys/module
Locking apps to stay in memory (making it resident)
a) Using App Settings (Xposed)
- One simple method is used Xposed module, App settings (you need Xposed framework installed)
- After installing the framework, then download the 'App Settings' module through Xposed installer.
- Open App Settings and allow the applications to load, selected the target app (in this case firefox browser)
- In the settings page, enable the toggle and activate editing mode, tick the “Resident” option and save. (Making apps resident, causes apps to staying memory without being killed and it is advised to use exit button in target application if it’s no longer needed otherwise it will deprive other apps memory)
b) Using memory locker
Another implementation of this concept is locking the target application in memory by controlling the system files for setting oom_adj
for all running processes.
How the application works:
Memory locker controls files in the /data directory and also controls
sytem files in root for setting oom_adj for running processes.
All
locked applications are automatically locked after each reboot. Apps
are classified as downloaded/system apps, to unlock select target app
and click on the lock on right side. (You can optionally set oom_adj
priority)
Overriding the hidden app limit
In addition the low memory killing mechanism, there is another parameter that controls killing of hidden and empty apps. Apps are killed when they go beyond specified limits.
There is a build.prop setting that which can control this (default is usually a low number less than 25, and modifying this can increase this value to a much larger value like 80)
Add this line to build.prop file in /system and leave another blank line below that (be sure to make back up first)
ro.sys.fw.bg_apps_limit=80
References and Credits
- Android RAM Management (Special credits: mrhnet)
- Memory Locker
- Xposed - General info, versions & changelog