• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Root Memory recovery mechanism


Well-Known Member
Apr 2, 2012


Android is a Linux kernel, the operating system for mobile terminals. In order to meet the special needs as a mobile platform, operating system, Google to do their special design and optimization of process scheduling and resource management of Linux and other platforms have obvious difference. Mainly includes the following several levels:

Application Framework
Application Framework will the entire operating system separated into two parts. For application developers, all APP is running above the Application Framework, which need not be concerned about the bottom of the system. For application developers, the Application Framework layer provides a rich application programming interface, such as the Activity Manager, Content the Provider, Notification Manager, and a variety of window Widget resources. In the Application Framework layer, Activity is one of the most basic component of APP. Generally speaking, each Activity corresponds to a view on the screen (or screen), an APP can have one or more of the Activity. The application is packaged into the apk file formats, explained by the Dalvik VM execution.

Dalvik VM
Dalvik virtual machine register architecture, rather than the JVM stack structure. Java program compiled class files and can not be explained in the Dalvik execution. Google offers a dx tool, used to. Class files to convert Dalivk able to identify. Dex format. The specific details of the Dalvik VM is not the focus of this article, the following is no longer discussed.

Linux kernel
From the above, all of the APP are written in the Java code and explain the implementation in the Dalvik VM. Android operating system, each of the Dalvik VM Instance corresponds to a process in the Linux kernel. Can use adb shell tool to view the current process in the system. As shown below, the list of processes in the kernel Android2.3.3 start.

Figure 1 in Android 2.3, the list of processes (in part)

Figure 1, the UID identifies a app_xx each app are occupied by the process, we can see the Android design allows each application to explain the implementation by an independent instance of the Dalvik, and each process of the Linux kernel to load a Dalvik instance, by in this way to provide the operating environment of the app. So, the resources of each APP is completely shielded, without disturbing each other. Although the introduction of the difficulties of inter-process communication, but it also brings greater security.

Android memory recovery principles

The following from the Application Framework and Linux kernel-level analysis of the Android operating system resource management mechanism.

Android has been adopted special resource management mechanism, because the beginning is that its design for mobile terminals, all the available memory is limited in the system RAM, design optimization program for this restriction. When Android application exits, does not clean up the memory occupied by the Linux kernel process, the continued existence of the so-called "exit but does not close. Allowing the user to the calling program can get a response the first time. When the system memory, the system will activate the memory recovery process. In order not to affect the user experience because of memory recovery (such as kill the current active process), Android running in a process-based components and their status provides a default priority of the five recycling:






Several priority recovery order is Empty process, Background process, Service process, Visible process, Foreground process. Classification Principles the See Processes and Threads | Android Developers file.

ActivityManagerService centralized management of all processes of memory resource allocation. All processes need to apply or release the memory before call ActivityManagerService object, get the "license" to the next step, or will be directly ActivityManagerService "do it". Several important members of class ActivityManagerService involved in memory recovery as follows: trimApplications (), updateOomAdjLocked (), activityIdleInternal (). Several members primarily responsible for the Android default memory recovery mechanism, if the Linux kernel memory recovery mechanism is disabled, skip the default recycling.

The default recovery process

Memory recovery in the Android operating system can be divided into two levels, which is the default memory recovery and kernel-level memory recovery This chapter focuses on the default memory recovery mechanism, the Linux kernel-level memory-recovery mechanisms in the next one introduced. All of the code of the chapter to see ActivityManagerService.java.

The entrance of the recycling movement: activityIdleInternal ()

The trigger point of the memory recovery in the Android system can be divided into three cases. First, the user program call StartActivity (), the Activity of the current activities cover; Second, the user presses the back button to exit the current application; Third, start a new application. These events can trigger the memory recovery end up calling function interface is activityIdleInternal (). When ActivityManagerService received asynchronous message IDLE_TIMEOUT_MSG or IDLE_NOW_MSG activityIdleInternal () will be invoked. Code as follows:

List 1. IDLE_NOW_MSG approach

case IDLE_NOW_MSG: {
IBinder token = (Ibinder) msg.obj;
activityIdle (token, null);

List 2. IDLE_TIMEOUT_MSG approach

if (mDidDexOpt) {
mDidDexOpt = false;
Message nmsg = mHandler.obtainMessage (IDLE_TIMEOUT_MSG);
nmsg.obj = msg.obj;
mHandler.sendMessageDelayed (nmsg, IDLE_TIMEOUT);
IBinder token = (IBinder) msg.obj;
Slog.w (TAG, "Activity idle timeout for" + token);
activityIdleInternal (token, true, null);

IDLE_NOW_MSG events triggered by the switching of Activity and Activiy focus changes the IDLE_TIMEOUT_MSG raised Activity start timeout, in general, this timeout is set to 10s, 10s of an Activity still did not start successfully, it will send an asynchronous message IDLE_TIMEOUT_MSG conduct resource recycling. activityIdleInternal () main task is to change the system Activity status information, and added to the list of different states. Its main tasks are as follows:

First, the call scheduleAppGcsLocked () method notifies all the tasks for garbage collection. scheduleAppGcsLocked () scheduling the JVM garbage collect recycling part of the memory space, only to inform each process check their own process of garbage and scheduling the recovery time, rather than synchronized recovery. Then, take out all the content in the the mStoppingActivities and mFinishigActivities list, temporary storage in a temporary variable. The two lists were stored in the object of the current activity status for the stop and finishi. Stop list, if the activity finish state is true, the judgment is not to stop immediately, if you want to stop immediately call destroyActivityLocked () notify the target process the call onDestroy () method, otherwise the first the call resumeTopActivity () to run the next Activity . If the finish state is false, then call stopActivityLocked () to notify the client process to stop the the Activity, this situation generally occurs after calling startActivity (). For the finish list directly the call destroyActivityLocked () to notify the client process to destroy the goal of the Activity.

Here destroyActivityLocked function and no change in the true sense of the use of memory, only to change its state to allow recycling, recycling the following will call trimApplications of () function.

Recycling process function trimApplications ()

trimApplications () function is structured as follows:

Listing 3. TrimApplications function

private final void trimApplications () {
synchronized (this) {
/ / First remove any unused application processes whose package
/ / Has been removed.
for (i = mRemovedProcesses.size () -1; i> = 0; i -) {
(1) / / kill process;
if (! updateOomAdjLocked ()) {
(2) / / do something default
/ / Finally, if there are too many activities now running, try to
/ / Finish as many as we can to get back down to the limit.
(3) do something

Listing 3 in the three standard serial number location are responsible for the following work:

(1) When the program execution to trimApplications (), the first check the mRemovedProcesses list process. mRemovedProcesses list consists mainly of the crash process, and selected by the user forced to shut down the process, as well as application development this the call killBackgroundProcess want to kill the process did not respond within 5 seconds. The call Process.killProcess kill all such processes.

(2) the call updateOomAdjLocked () function, if successful return, indicating that the Linux kernel to support setOomAdj () interface, updateOomAdjLocked will modify the value of the adj and notify the linux kernel, the kernel according to adj values, and memory usage of the dynamic management process resources (lowmemorykiller,, and oom_killer) . The the if updateOomAdjLocked () returns false, it means that the current system does not support setOomAdj () interface, in the local default resource recovery.

(3) Finally, if the current is still running too much Activity recovery of excess Activity. most trimApplications () code does not exist in processing Oom_killer, in case of default resource recovery, the following default recovery process (ie, marked in the code list position (2)) for further analysis. The recycling process can be broadly described below.


Step one, get all the current running processes mLruProcesses mLruProcesses collation of recent use of time. MLruProcesses in the process can not be counted, the process can not be closed, including the process of running the service, run the process of the broadcast receiver, etc., see the following code.

Listing 4. Count process can not be closed

if (app.persistent | | app.services.size ()! = 0
| | App.curReceiver! = Null
| | App.persistentActivities> 0) {
/ / Don't count processes holding services against our
/ / Maximum process count.
numServiceProcs + +;

Step 2, set the current maximum number of running processes curMaxProcs = curMaxProcs + numServiceProcs (the default maximum number of processes running Service, the number of processes), if the current process the number mRemovedProcesses.size () is greater than this value, the traversal of all currently running process, kill those who meet the requirements process and free memory. The cleaning process as shown in Listing 5 (part of the code omitted). From the code in Listing 5 can be seen that the process is killed on condition that:

Must be non-persistent process, that is, non-system processes;
Must be an empty process, the process of no activity. If you kill a process exists Activity, it is possible to close the user is using the program, or the larger the delay of recovery applications, thus affecting the user experience;
Must broadcast receiver. Run the broadcast receiver is generally waiting for the occurrence of an event, the user does not want such a program was forced to close;
Service number of the process must be 0. The service process is likely for one or more programs to provide certain services, such as GPS location-based services. Kill such a process will allow other processes can not be normal service.
The above conditions are indispensable.

Listing 5. Cleaning process

if (! app.persistent && app.activities.size () == 0
&& App.curReceiver == null && app.services.size () == 0) {
if (app.pid> 0 && app.pid! = MY_PID) {
Process.killProcess (app.pid);
} Else {
try {
app.thread.scheduleExit ();
} Catch (Exception e) {
/ / Ignore exceptions.
/ / Todo: For now we assume the application is not buggy
/ / Or evil, and will quit as a result of our request.
/ / Eventually we need to drive this off of the death
/ / Notification, and kill the process if it takes too long.
cleanUpApplicationRecordLocked (app, false, i);
i -;

Step 3, once again check the currently running process, if mRemovedProcesses.size () is still larger than curMaxProcs is to relax the conditions to be recycled again. Judgment conditions see Listing 6 (part of the code omitted). The following code in Boolean variable canQuit the value true, then this process can be recycled. canQuit values ​​in two steps, the first is based on the properties of the process of assignment. One must be non-persistent process, that is, non-system processes; 2 must be non-broadcast receiver; the process of service the number must be 0; a persistent type of activity the number of 0. Step two the only difference in the first four, does not require that the process is the empty process, as long as the process does not have the persistent type of Activity (Activity Is persistent type specified in the development stage). These conditions are met, then check the properties of each Activity in the process when the process all the Activity must meet three conditions: Activity 's the state has been saved in not visible and Activity has been the Stop. Then kill the process will reduce the loading speed when the next call to the program, the next boot will be restored to the state before closing, and will not cause a fatal impact on user experience, so canQuit set to true. This situation and steps of recovery is different, Activity in the process the number is not 0, the next step for each activity destroyActivityLocked () destroyed, and finally kill the process.

Listing 6. The execution destroyActivityLocked () destroyed

boolean canQuit =! app.persistent && app.curReceiver == null
&& App.services.size () == 0
&& App.persistentActivities == 0;
int NUMA = app.activities.size ();
for (j = 0; j <NUMA && canQuit; j + +) {
HistoryRecord r = (HistoryRecord) app.activities.get (j);
canQuit = (r.haveState | |! r.stateNotNeeded)
&&! R.visible && r.stopped;
if (canQuit) {
/ / Finish all of the activities, and then the app itself.
for (j = 0; j <NUMA; j + +) {
HistoryRecord r = (HistoryRecord) app.activities.get (j);
if (! r.finishing) {
destroyActivityLocked (r, false);
r.resultTo = null;
if (app.pid> 0 && app.pid! = MY_PID) {
Process.killProcess (app.pid);
cleanUpApplicationRecordLocked (app, false, i);
i -;
/ / Dump ();

Step four, three of the above process is carried out for the entire process recycling. Activity resources for recycling in the above process is finished, in the smaller particle size. Similar to those described above, the list mLRUActivities storage all currently running Activity collation is the same as the principle of least access. mLRUActivities.size () returns the number of running on the system Activity, when it is greater than MAX_ACTIVITIES (MAX_ACTIVITIES is a constant, the general value of 20 on behalf of the system allows simultaneous Activity). Recycling part to meet the conditions of the Activity to reduce memory usage. Recovery condition code shown in Listing 7:

Listing 7. Recovery condition code

/ / Finally, if there are too many activities now running, try to
/ / Finish as many as we can to get back down to the limit.
for (i = 0;
i <mLRUActivities.size ()
&& MLRUActivities.size ()> curMaxActivities;
i + +) {
final HistoryRecord r
= (HistoryRecord) mLRUActivities.get (i);

/ / We can finish this one if we have its icicle saved and
/ / It is not persistent.
if ((r.haveState | |! r.stateNotNeeded) &&! r.visible
&& R.stopped &&! R.persistent &&! R.finishing) {
final int origSize = mLRUActivities.size ();
destroyActivityLocked (r, true);
if (origSize> mLRUActivities.size ()) {
i -;

Here just recovered Activity, memory resources, and will not kill the process, it will not affect the operation of the process. When the process need to call the Activity to be killed, you can save the state response, of course, may take a relatively a little longer delay.

Linux kernel memory recovery


Mentioned above, trimApplications () function will perform one called updateOomAdjLocked the () function If false, perform the default recovery, if returns true not perform the default memory recovery. updateOomAdjLocked update a variable called adj for each process, and inform the Linux kernel, the kernel maintains a data structure (ie, the process table) a adj, and through lowmemorykiller check the system memory usage in low memory conditions kill some process and release the memory. The following will be this Android Framework with the Linux kernel matching memory recovery mechanism.

Android operating system, all applications run independent of the Dalvik virtual machine environment, the Linux kernel can not be informed of the operational status of each process, will not be able to maintain an appropriate adj value for each process, therefore, the Android Application Framework must provide a mechanism to dynamically update each process adj. This is updateOomAdjLocked ().

updateOomAdjLocked () is located in ActivityManagerService, its main role for the process to select a suitable adj value, and notify the Linux kernel to update this value. updateOomAdjLocked call First computeOomAdjLocked () preliminary calculations adj value of then back updateOomAdjLocked the (further amended) of its value. The estimation process can be found in the code.

Adj, which is defined in task_struct-> signal_struct-> adj, file / kernel / include / linux / sched.h. The essence of a variable in the process data structure used to represent the priority of the order to kill the process in the case of Out of Memory. lowmemorykiller use this variable to judge the degree of importance of the process, free up some space in the memory is insufficient, in fact, file / kernel / drivers / staging / android / lowmemorykiller.c in. lowmemorykiller defines two arrays: lowmem_adj and lowmem_minfree. Which lowmen_adj defines a series of adj key, each element lowmem_minfree in behalf of a memory threshold. Four threshold in the following code is 6MB, 8MB, 16MB and 64MB, representing the memory less than 64MB, adj greater than or equal to 12, those processes will be killed and recovered memory less than 16MB, adj greater than equal to six of those processes will be killed and recovery, memory is less than 8MB, adj greater than or equal to those processes will be killed and recovery, memory is less than 6MB, adj greater than or equal to 0, all processes will be killed death and recovery. Each process in the kernel holds a adj range of -17 to 15, the value the higher the importance of the smaller representatives of the process, the lower recovery priority -17 on behalf of disabled automatic recovery. Android system, only 0-15 is used.

Listing 8. Each process holds an adj

static int lowmem_adj [6] = {
static int lowmem_adj_size = 4;
static size_t lowmem_minfree [6] = {
3 * 512, / * 6MB * /
2 * 1024, / * 8MB * /
4 * 1024, / * 16MB * /
16 * 1024, / * 64MB * /
static int lowmem_minfree_size = 4;

lowmemorykiller registered the one lowmem_shrinker lowmem_shrinker use the standard Linux kernel Cache Shrinker, when the lack of free memory pages, the kernel thread kswapd registered lowmem_shrinker to reclaim the memory page.

List. Registered lowmem_shrinker to reclaim the memory page

static struct shrinker lowmem_shrinker = {
. Shrink = lowmem_shrink,
. Seeks = DEFAULT_SEEKS * 16

static int __ init lowmem_init (void)
task_free_register (& task_nb);
register_shrinker (& lowmem_shrinker);
return 0;

code in lowmem_shrink the function lowmem_shrink, are given below the main structure of the function. lowmem_shrink traverse all the processes under such rules, elect the need to end the process, send a not ignore the SIGKILL signal to force the end of these processes

Listing 10 to force the end of the process

static int lowmem_shrink (struct shrinker * s, int nr_to_scan, gfp_t gfp_mask)
for_each_process (p) {
/ / Select processes to be forced
if (selected) {
force_sig (SIGKILL, selected);
rem - = selected_tasksize;
} Else
rem = -1;
return rem;


If the above methods can not release enough memory space, then when the application for the new process allocation Out of Memory exception OOM_killer will last-ditch effort to kill the process to free up space. In Android OOM_killer inherited from the standard Linux 2.6 kernel, is used to allocate memory Out of Memory handling. Android and its implementation to be modified. Its location in linux / mm / oom_kill.c. oom_killer through the process, and calculate the badness value of all processes, select the badness that process the biggest kill. Function badness of the following statement:

unsigned long badness (struct the task_struct * an unsigned long the uptime) function select_bad_process return to kill that process.

Listing 11 returns to kill the process

static struct task_struct * select_bad_process (unsigned long * ppoints,
struct mem_cgroup * mem)
for_each_process (p) {
points = badness (p, uptime.tv_sec);
if (points> * ppoints | |! chosen) {
chosen = p;
* Ppoints = points;
return chosen;

Finally, and lowmemorykiller by sending SIGKILL to the end of the selected process. Standard Linux kernel due oom_killer, there is no difference here is no longer studied in detail.


This paper studies the memory recovery mechanisms on the Android operating system. In default of the Application Framework layer recovery as well as the Linux kernel lowmemorykiller OOM_killer. General, application developers do not need to control or modify the system's memory management and recycling, but in-depth understanding of these system-level management mechanism is still necessary, in particular, contribute to a more reasonable design of the application, the application process in its efficient operation within the life cycle. System-level developers to optimize the memory management mechanism, the understanding of the original mechanism is an important prerequisite is essential.

  • Like
Reactions: darbhadinesh


We've been tracking upcoming products and ranking the best tech since 2007. Thanks for trusting our opinion: we get rewarded through affiliate links that earn us a commission and we invite you to learn more about us.