Android operating system, memory recovery mechanism.

Reprinted from the product is slightly net: http://www.pinlue.com/article/2020/03/0808/089994336918.html

Android APP operating environment

Android is a Linux-based kernel, the operating system for mobile terminals. In order to meet their special needs as a mobile platform operating system, Google made its special design and optimization, so that its process scheduling and resource management and other Linux platforms significantly different. Mainly includes the following several levels:

Application Framework

Application Framework entire operating system is divided into two portions. Application developers, APP are all run on Application Framework, and the system does not need to care about the underlying. Application Framework layer application developers to provide a rich application programming interfaces, such as the Activity Manager, Content Provider, Notification Manager, and a variety of resources for the Widget window. In the Application Framework layer, Activity is a fundamental part of APP. Activity generally each correspond to a view screen (or a screen), there may be one or a plurality of APP Activity. Application is packaged into a file format .apk interpreted by Dalvik VM executed.

Dalvik VM

Dalvik virtual machine register architecture, rather than a stack structure JVM. .class files compiled Java programs can not be interpreted in the Dalvik. Google dx thus provides a tool for converting Dalivk .class files into formats that can be identified .dex. Dalvik VM specific details are not the focus of this article, the following will not be discussed.

Linux kernel

All APP are written by the Java code executed and explained in Dalvik VM. In the Android operating system, each Instance each Dalvik VM is a process corresponds to the Linux kernel. You can use adb shell tool to view the current process system. , Android2.3.3 process list after starting the kernel shown below.

FIG process list (portion) of 1. Android 2.3

In FIG 1, UID identifies app_xx of each app is occupied by a process, visible Android designed such that each application consists of a separate instance Dalvik interpreted, and each process loads a Linux kernel Dalvik example, by the app provides a runtime environment in this way. Thus, each of the APP resources are fully shielded, without disturbing each other. Although difficulties while introducing inter-process communication, but it also brings greater security.

Android memory recovery principles

Application Framework and the following two levels of analysis of Linux kernel resource management mechanism from the Android operating system.

Android has been adopted special resource management mechanism, since it is the beginning of the design for the mobile terminal, all available memory is limited to system RAM, the corresponding optimization program must be designed for such restrictions. When Android application exits, it does not clean up the memory occupied, Linux kernel process accordingly continue to exist, so-called "exit but do not close." It can be obtained at a first time in response to a user so that the calling program. When the system memory is low, the system will activate the memory recovery process. In order not to affect the user experience (such as killing the current active processes) due to memory recall, Android-based components and their status in the process of running a default provision of five recycling priority:

IMPORTANCE_FOREGROUND:

IMPORTANCE_VISIBLE:

IMPORTANCE_SERVICE:

IMPORTANCE_BACKGROUND:

IMPORTANCE_EMPTY:

These types of recovery priority order is Empty process, Background process, Service process, Visible process, Foreground process. See http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html on the principle of division of files.

ActivityManagerService centralized management of all processes of memory resource allocation. To the next step after the object must be called before ActivityManagerService all processes need to apply or release the memory, get their "permission" or ActivityManagerService will direct "do it." Class ActivityManagerService several important members of memory reclamation method involves the following: trimApplications (), updateOomAdjLocked (), activityIdleInternal (). This method is mainly responsible for several members of the Android default memory recovery mechanism, if the garbage collection mechanism in the Linux kernel is not disabled, skip default recovery.

Default recovery process

Memory recall Android operating system can be divided into two levels, which is the default memory recall and kernel-level memory recovery, this chapter focuses on the default memory recovery mechanism research, Linux kernel-level memory recovery mechanism will be introduced in the next one. All the code in this chapter can be found ActivityManagerService.java.

Inlet recovery operation: activityIdleInternal ()

Android trigger memory reclamation system can be divided into three cases. First, the user program calls StartActivity (), the currently active Activity is covered; second, the user presses the back key to exit the current application; third, to start a new application. These events can trigger function interface memory recovery of final call is activityIdleInternal (). When receiving the asynchronous message IDLE_TIMEOUT_MSG ActivityManagerService or IDLE_NOW_MSG, activityIdleInternal () will be called. code show as below:

Listing 1. IDLE_NOW_MSG of treatment

1

2

3

4

5

case IDLE_NOW_MSG:{

IBinder token = (Ibinder)msg.obj;

activityIdle(token, null);

}

break;

Listing 2. IDLE_TIMEOUT_MSG of treatment

1

2

3

4

5

6

7

8

9

10

11

12

13

case IDLE_TIMEOUT_MSG: {

if (mDidDexOpt) {

mDidDexOpt = false;

Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);

nmsg.obj = msg.obj;

mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);

return;

}

IBinder token = (IBinder)msg.obj;

Slog.w(TAG, "Activity idle timeout for " + token);

activityIdleInternal(token, true, null);

}

break;

IDLE_NOW_MSG caused by the switch and change Activiy focus of events such as Activity, IDLE_TIMEOUT_MSG start initiator timeout case in Activity, generally the timeout to 10s, the 10s if the Activity is still not a successful start, it will be sent asynchronous message IDLE_TIMEOUT_MSG Recycle. activityIdleInternal () main task is to change the system state information Activity, and adds it to the list of different states. Its main work is as follows:

First, call scheduleAppGcsLocked () method notifies all ongoing tasks for garbage collection. scheduleAppGcsLocked () will dispatch the JVM garbage collect, recovering a portion of the memory space, where each process is only to inform their own inspection process garbage and recycling schedule time, rather than synchronous recovery. Then, remove all contents mStoppingActivities and mFinishigActivities list, temporarily stored in a temporary variable. These two lists are stored to stop the current state of activity and finishi objects. For the stop list, finish state if one of the activity's true, the judge is not to be stopped immediately, if you want to immediately stop the call destroyActivityLocked () notifies the target process calls onDestroy () method, otherwise, the first call resumeTopActivity () next run an Activity . If the finish state is false, the call stopActivityLocked () to inform the client process to stop the Activity, which generally occurs after the call startActivity (). For the finish list, direct call destroyActivityLocked () to inform the client process to destroy the target Activity.

Here destroyActivityLocked functions such as memory usage does not change the true sense, but its status is changed to "allow recovery", trimApplications real recovery in the following upcoming call (function).

Recovery process function trimApplications ()

trimApplications () function has the following structure:

Listing 3. trimApplications function

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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 position in the three standard serial number are responsible for the following tasks:

After (1) When the program execution to trimApplications (), first check process mRemovedProcesses list. mRemovedProcesses list mainly includes a process crash, there is no response and the user selected in the forced shutdown process, as well as application development which calls killBackgroundProcess want to kill the process within five seconds. All such calls Process.killProcess will kill all processes.

(2) call updateOomAdjLocked () function, if successful return, indicating the Linux kernel support setOomAdj () interfaces, updateOomAdjLocked will modify the value adj and notify the linux kernel, dynamic management process resources (lowmemorykiller and oom_killer) according adj value and memory usage . If updateOomAdjLocked () returns false, then the current system does not support setOomAdj () interface will be the default resource recovery locally.

(3) Finally, if the current is still running too many Activity, recycling of excess Activity. Most code trimApplications () are by default in the recycling process Oom_killer in the absence of, the following further analyzed (i.e. Listing marked position (2)) of the default recovery process. Recovery process which may be generally described as follows.

Step one, get all currently running processes mLruProcesses, mLruProcesses of the collation is based on recent usage time. MLruProcesses can not be closed on the counting process, these processes can not be closed include a service operation process, a process running broadcast receiver or the like, see the following code.

Listing 4. The counting process can not be closed

1

2

3

4

5

6

7

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 two, set the current maximum number of processes running curMaxProcs = curMaxProcs + numServiceProcs (which is the default number of processes and the maximum number of processes running and Service), if the current number of processes mRemovedProcesses.size () is greater than this value, then traverse all currently running process, kill the process of qualifying and free up memory. Cleanup process is shown in Listing 5 (part code is omitted). As can be seen from the code in Listing 5, the process is killed conditions are:

We must be non-persistent process, that is, non-system processes;

Must be an empty process, that process does not exist any activity. If the process of killing Activity exist, it is possible to close the program being used by the user or the application back delay increases, thus affecting the user experience;

You must not broadcast receiver. Run broadcast receiver generally are waiting for an event to occur, the user does not want these programs to be forced to shut down the system;

The number of processes in service must be 0. There is service of process is likely to provide a service for the service in one or more programs, such as GPS positioning. Such a process will kill other processes can not serve properly.

The above conditions are indispensable.

Listing 5. cleanup process

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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 three, check the current running process again, if mRemovedProcesses.size () is still greater than curMaxProcs, then relax the conditions for recycling again. Analyzing conditions see Listing 6 (omitted portions of code). The following code, the value of Boolean variable canQuit true, then the process can be recycled. canQuit values ​​in two steps, the first is based on the attribute assignment process. 1. The process must be non-persistent, i.e., non-system processes; 2 must be free broadcast receiver;. 3 Process Number of service must be 0; The number of types of activity 4 persistent 0. The only difference is step two in Article 4, where the process is not required to empty the process, as long as the process is not persistent type of Activity will be (whether it is persistent Activity type specified in the development phase). When these conditions are met, then the process of checking the attributes of each Activity, and when that process all the Activity must also meet three conditions: Activity of the state has been saved, not visible in the current state and Activity has Stop. Then kill the process will reduce the loading speed when the next caller will be restored to the state before the next time you start off, and will not cause a fatal impact on the user experience, so, canQuit set to true. This situation is step two recovery methods are different, due to the number Activity is not 0, the next step needs to be performed for each activity destroyActivityLocked process () destroyed, and finally kill the process.

Listing 6. Executing destroyActivityLocked () destroyed

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

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 4 The above three recycling process is performed for the entire process. After the above process is finished, the recycling of resources Activity in smaller particle size. Similar to the above, all of the currently stored list mLRUActivities running Activity, collation principle the same as the minimum access. mLRUActivities.size () returns the number of the Activity running on the system, when it is more than MAX_ACTIVITIES (MAX_ACTIVITIES is a constant, the general value of 20 indicates that the system's maximum allowable simultaneous Activity). The recovery section in order to satisfy the condition of Activity reduce memory usage. 7 Recycling Conditions Listing:

Listing 7. Recycling condition code

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

//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--;

}

}

}

Activity here just recovered memory resources, and does not kill the process, it will not affect the operation of the process. When a process needs to be called to be killed Activity, you can restore from a saved state, of course, may require relatively little long delay.

Linux kernel memory recovery

lowmemorykiller

Mentioned above, trimApplications () function will execute the function called updateOomAdjLocked (), and if it returns false, then execute the default recovered, returns true if the garbage collection is not performed by default. updateOomAdjLocked will update a variable named adj for each process, and inform the Linux kernel, which contains adj maintain a data structure (ie, the process table), and by the use of lowmemorykiller check the system memory in low memory conditions under kill some process and free up memory. The following will be the Linux kernel memory recovery mechanisms cooperate to study this Android Framework.

Since all applications Android operating system runs in standalone Dalvik virtual machine environment, Linux kernel does not know the operational status of each process, it can not maintain a proper adj value for each process, therefore, Android Application Framework We must provide a mechanism to dynamically update each process adj. This is updateOomAdjLocked ().

updateOomAdjLocked () located in ActivityManagerService, whose main role is to select an appropriate value adj process, and notify the Linux kernel update this value. updateOomAdjLocked first call computeOomAdjLocked () value adj preliminary calculations, and then return to updateOomAdjLocked () its value further amendments. See the code estimation process.

About adj, which is defined in task_struct-> signal_struct-> adj, file /kernel/include/linux/sched.h in. In real terms as a process variable data structure used to represent the order of priority of the process occurs when the Out of Memory killed. lowmemorykiller use this variable to judge the importance of the process and free up some space in low memory conditions, in fact, file /kernel/drivers/staging/android/lowmemorykiller.c. lowmemorykiller defines two arrays: lowmem_adj and lowmem_minfree. Wherein lowmen_adj adj defines a series of keys, with each element representing a lowmem_minfree memory threshold. In the following code is four threshold values ​​6MB, 8MB, 16MB and 64MB, respectively represent when the memory is less than 64MB, ADJ greater than or equal to those of the process 12 will be killed and recovered, the memory is less than 16MB, adj is greater than or equal to those 6 when the process will be killed and recovered memory is less than 8MB, adj those processes greater than or equal to 1 and recovered will be killed when the memory is less than 6MB, adj greater than or equal to 0 all processes are killed and recovered. The higher the importance of each process in the kernel are in possession of a adj, ranging from -17 to 15, the smaller the value represents the process of recovering lower the priority, which represents the -17 disable automatic recovery. Android system, only 0-15 are used.

Listing 8. Each process holds a adj

1

2

3

4

5

6

7

8

9

10

11

12

13

14

static int lowmem_adj[6] = {

0,

1,

6,

12,

};

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 a lowmem_shrinker, lowmem_shrinker Cache Shrinker use the standard Linux kernel to achieve, when there is insufficient free memory pages, the kernel thread kswapd with lowmem_shrinker registered to reclaim memory page.

Listing 9. Use lowmem_shrinker registered to reclaim memory page

1

2

3

4

5

6

7

8

9

10

11

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;

}

lowmem_shrink lowmem_shrink function code, the function of the main structure of the following is given. lowmem_shrink through all the processes according to the above rules, elect the need to end the process by sending a signal SIGKILL can not be ignored mandatory end them

Listing 10. terminates the process

1

2

3

4

5

6

7

8

9

10

11

12

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;

}

Oom_killer.

If the above methods can not free up enough memory space, then when assigning an application for a new process to Out of Memory anomaly, OOM_killer will make a final effort to kill some processes to free up space occurs. Android OOM_killer inherited from the standard Linux 2.6 kernel, when allocating memory for processing Out of Memory. Android does not modify its implementation. Its position in the linux / mm / oom_kill.c. oom_killer traversal process, and calculates the badness values ​​of all processes, select badness of that process will be the largest of its kill. Function badness of the following statement:

unsigned long badness (struct task_struct * p, unsigned long uptime) function returns select_bad_process that the process will be killed.

Listing 11. Returns to kill the process

1

2

3

4

5

6

7

8

9

10

11

12

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 as the selected process by sending SIGKILL end. Due to the different oom_killer the standard Linux kernel, there is no study in detail here no longer.

to sum up

In this paper, garbage collection mechanism on the Android operating system. Application Framework including recovering default layers and Linux kernel lowmemorykiller, OOM_killer. In general application developers do not need to control or modify the system memory management and recycling, but in-depth understanding of these system-level management mechanism is still necessary, in particular, contribute to a more rational design of the application, the application process in its run the life cycle efficiently. Developers and system-level memory management mechanism if you want to optimize the original understanding of the mechanisms is an indispensable prerequisite.

 

Published 60 original articles · won praise 52 · views 110 000 +

Guess you like

Origin blog.csdn.net/yihuliunian/article/details/104729646