In daily development, it is common for testers and developers to argue with each other: “Why does the page content have to be reloaded when it is returned from another app? This must be a bug”, “Activity was recycled by the system, it is not a bug”; “Why switch to the background, the app heartbeat is not online, this must be a bug”, “this is the background process was recycled by the system, what a bug”. Memory reclamation is a common concept in Android development, but do you really know anything about it? In this article, we will briefly explore the memory reclamation mechanism of Android.

Android memory reclamation mechanism

Addroid system is designed from the perspective of user experience and performance optimization. LMK mechanism is designed: Low Memory Killer (LMK for short), which is used to process Memory reclamation scheduling.

Is simply, when the app to switch to the background, in order to carry on the user to open the app again, to respond in a timely manner to speed up the app open time, the Android system to switch to the background of the app, does not immediately kill the recovery, but in the case of guarantee system resources enough, as far as possible the ascension of the app process in the system memory retention time, Only when the system memory resources are insufficient, the APP process can be reclaimed according to a certain priority. This mechanism is CALLED LMK.

Android Process Classification

The Android system classifies app processes according to the current status of the app, the running declaration period of the component, and the importance of the process.

Before Android 5.0, the system divides app processes into five categories:

  • Foreground process —IMPORTANCE_FOREGROUND
    • In simple terms: the process that the current user is working on.
    • For example, any of the following are considered foreground processes:
      • It’s running one on the user’s interactive screenActivity(theonResume()Method already called).
      • It has oneBroadcastReceiverCurrently running (itsBroadcastReceiver.onReceive()Method executing).
      • It has oneServiceCurrently executing one of its callbacks (Service.onCreate(),Service.onStart()Service.onDestroy()).
  • Visible process —IMPORTANCE_VISIBLE
    • It is performing a task that the user is currently aware of, that is, a process that the user is aware of.
    • Such as:
      • It’s runningActivityVisible to the user on the screen, but not in the foregroundonPause()Method already called). For example, this might happen if the foreground Activity is displayed as a dialog box that allows the previous Activity to be seen behind it.
      • It has oneServiceIs throughService.startForeground()(requires the system to treat the service as a service that the user knows about or is essentially visible to the user) running as a foreground service.
      • The system is using its hosted services to implement user-aware specific functions, such as dynamic wallpaper, input method services, and so on.
  • Service process —IMPORTANCE_SERVICE
    • Contains one already in usestartService()Method startedService.
    • Note:
      • A Service process is a separate process in which no Activity is started.
      • Service processes that have been active in the last 30 minutes.
  • Background process —IMPORTANCE_BACKGROUND
    • Apps switch to the background, and apps usually contain one or more that are not currently visible to the userActivityInstance (onStop()Method has been called and returned).
  • Blank process —IMPORTANCE_EMPTY

Of course, in The Android system after 5.0, the process classification is again refined, such as:

  • Android 5.0, new
      • IMPORTANCE_PERCEPTIBLE
      • IMPORTANCE_CANT_SAVE_STATE
      • IMPORTANCE_CACHED
        • Is equivalent toIMPORTANCE_BACKGROUND
    • For Android 11.0, there are nine
      • IMPORTANCE_TOP_SLEEPING
        • Foreground APP, but the system entered hibernation, this APP process.
      • IMPORTANCE_FOREGROUND_SERVICE
        • willService.startForeground()The front desk service has been split, single column.

Here is not introduced in detail, can pass source: android. App. ActivityManager. RunningAppProcessInfo the definition and annotation view detailed introduction.

ADJ

When the system memory resources are insufficient, the system will reclaim the APP process according to a certain priority. The priority is ADJ.

When an App process is started, the Android system assigns an independent ADJ to it. The value of ADJ changes dynamically with the status of the process and the life cycle of its components.

Viewing the System adj.

Android maintains a one-to-one mapping between the adj value and the available memory. When the available memory reaches the threshold, the corresponding ADJ value is reclaimed to release resources.

Minfree and ADJ files describe the relationship between the available memory of the system and the priority of the corresponding process. The two files are divided into multiple levels and their values are one-to-one.

aosp:/sys/module/lowmemorykiller/parameters # cat minfree
18432.23040.27648.32256.36864.46080
aosp:/sys/module/lowmemorykiller/parameters # cat adj
0.100.200.300.900.906
Copy the code

By looking at the sys/module/lowmemorykiller minfree and adj files under/parameters, can be used for memory threshold and adj. Take the above data as an example:

Note: The unit of menFree is page, 1page = 4K.

If the available memory is less than 46080 x 4/1024 = 180(M), the system reclaims the processes whose ADj is greater than 906 to release the memory. Similarly, if the available memory is less than 18432 x 4/1024 = 72 M, the system reclaims the processes whose ADJ is greater than 0.

Application Process ADJ

When an App process starts, the Android system assigns a separate adj. The size of the process adj. can also be viewed using the ADB command.

// Check the application process number
aosp:/ # ps |grep com.zhong.event
u0_a45    2104  1060  1153372 92444          0 c7f29c02 S com.zhong.event
// Check the adj. value of the process
aosp:/ # cat /proc/2104/oom_score_adj
// com.zhong.event is the foreground application, adb = 0
0
Copy the code

The value of process adj can be obtained by viewing the /proc/process ID /oom_score_adj file.

We hit the Home button to switch the app to the background and check its ADJ value again:

aosp:/ # cat /proc/2104/oom_score_adj
700
Copy the code

Kill the process manually and check again:

aosp:/ # cat /proc/2104/oom_score_adj
sh: cat: /proc/2104/oom_score_adj: No such file or directory
1|aosp:/ #
Copy the code

You can see that the adj value of a process changes dynamically, and the system allocates ADJ only when the application process is alive.

Note: The value of adj varies according to the system version and hardware configuration, but the relationship is the same.

Adj level

Adj. The adj. value dynamically changes according to the current APP status and the life cycle changes of the four components. The common levels are as follows:

The value of adj varies with Android versions, hardware configurations, and even manufacturers.

ADJ level The values meaning
NATIVE_ADJ – 1000. Native process
SYSTEM_ADJ – 900. Only the system_server process
PERSISTENT_PROC_ADJ – 800. System Persistent Process
PERSISTENT_SERVICE_ADJ – 700. Associated with systems or persistent processes
FOREGROUND_APP_ADJ 0 The foreground process that the user currently needs to perform the operation.
VISIBLE_APP_ADJ 100 Visible process, performing tasks that the user is currently aware of,
PERCEPTIBLE_APP_ADJ 200 Perceivable process, ForegroundService
BACKUP_APP_ADJ 300 The backup process
HEAVY_WEIGHT_APP_ADJ 400 Heavyweight process
SERVICE_ADJ 500 Service process, pure Service process
HOME_APP_ADJ 600 Home process, launcher app
PREVIOUS_APP_ADJ 700 Previous process
SERVICE_B_ADJ 800 B Service in the List. If resources are insufficient, the Service process is degraded
CACHED_APP_MIN_ADJ 900 Not visible minimum adj. for the process, activity Finish
CACHED_APP_MAX_ADJ 906 Maximum adj for invisible processes

Let’s focus on the bold parts of the table, and you can see that many of these types correspond to the Android process categories we described above.

adj < 0

These processes are basically processes handled by the system and do not require much attention. The only thing that needs to be noted is the case that PERSISTENT_SERVICE_ADJ. When the Android :persistent=”true” attribute is added to the app’s Androidmanifest.xml, The app must be a PERSISTENT_SERVICE_ADJ(-800) built-in app (under /system/ APP). If this condition is met, the system automatically creates an APP process upon startup. When a process is killed manually, the system also restarts the process automatically, which can be very effective when developing built-in applications.

FOREGROUND_APP_ADJ, adj = 0

The foreground process of the corresponding process type belongs to the case of adj = 0 when app meets any of the following conditions:

  • It’s running one on the user’s interactive screenActivity(theonResume()Method already called).
  • It has oneBroadcastReceiverCurrently running (itsBroadcastReceiver.onReceive()Method executing).
  • It has oneServiceCurrently executing one of its callbacks (Service.onCreate(),Service.onStart()Service.onDestroy()).

VISIBLE_APP_ADJ, adj = 100

Service. StartForeground () foreground Service

  • It’s runningActivityVisible to the user on the screen, but not in the foregroundonPause()Method already called). For example, this might happen if the foreground Activity is displayed as a dialog box that allows the previous Activity to be seen behind it.

PERCEPTIBLE_APP_ADJ, adj = 200

StartForeground Service process using service.startforeground ().

SERVICE_ADJ, adj = 500

Corresponding service process:

  • A Service process is a separate process in which no Activity is started.
  • Service processes that have been active in the last 30 minutes.

HOME_APP_ADJ, adj = 600

Home process, corresponding to the launcher property process, the application of type ACTIVITY_TYPE_HOME.

PREVIOUS_APP_ADJ, adj = 700

The last process used by the user (activity without Finish) is usually switched to the background application when the user switches between two apps.

Here, the concept of “previous” is not only the use of the previous app. For example, when the user switches from app A to app B and then from app B to app C, app A may be PREVIOUS_APP_ADJadj = 700.

CACHED_APP_MIN_ADJ, adj = 900

Corresponding to background process, APP switches to background:

  • Apps usually contain one or more that are not currently visible to the userActivityInstance (onStop()Method has been called and returned).
  • Typically, all activities are finished.

The other ad_types, most of which are special states of processes, will not be described in detail, but instead will refer to service_b_ad_types.

SERVICE_B_ADJ, adj = 800

The SERVICE_B_ADJ type is degraded to SERVICE_B_ADJ. In some special cases, such as insufficient resources, a Service process may be degraded to SERVICE_B_ADJ.

In addition, app processes of the same level and the same ADJ value are preferentially reclaimed by the system.

Quoting part of the official document:

Low memory terminates the daemon

Many times, KSWAPD does not free enough memory for the system. In this case, the system uses onTrimMemory() to inform the application that it is out of memory and should reduce its allocation. If this is not enough, the kernel starts terminating the process to free up memory. It uses the low memory termination daemon (LMK) to perform this operation.

LMK uses an “out of memory” score called oOM_ADJ_score to determine the priority of the running process, which determines which process to terminate. The process with the highest score is terminated first. Background applications are terminated first and system processes are terminated last. The following table lists the LMK score categories from high to low. The category with the highest rating, the items in the first row, will be terminated first:

Below is a description of the various categories in the table above:

  • Background application: A previously running application that is not currently active. LMK will be first from having the highestoom_adj_scoreThe application starts to terminate the background application.
  • Previous application: Recently used background application. The previous app has a higher priority (lower score) than the background app because the user is more likely to switch to the previous app than to a background app.
  • Home screen app: This is the launcher app. Terminating the application causes the wallpaper to disappear.
  • Services: Services are started by the application and may include synchronization or uploading to the cloud.
  • Perceptible applications: Non-foreground applications that the user can detect in some way, such as running a search process that displays a small interface or listening to music.
  • Foreground application: the application currently in use. Terminating a foreground app looks like the app crashed and may alert the user that there is a problem with the device.
  • Persistence (services) : These are the core services of the device, such as telephony and WLAN.
  • System: a system process. After these processes are terminated, the phone may appear to be about to restart.
  • Native: A very low-level process used by the system (for example,kswapd).

Device manufacturers can change the behavior of LMK.

More about ADJ detailed introduction and related introduction, can refer to the big man’s article: “interpretation of the Android process priority ALGORITHM”, explained in particular detailed, respect big man.

Service survival in terms of process reclamation

Understand the mechanism and principle of Android process recycling, the survival of the background service also has a certain inspiration, in simple terms, is as far as possible to improve the level of service process adj:

  • It can pass under special circumstancesandroid:persistent="true"Property to promote the process toPERSISTENT_SERVICE_ADJ(-800)Class, almost invincible. Of course, the condition is also very strict: the APP must be built into the system application.
  • Use the Front Desk serviceService.startForeground()To upgrade the process toPERCEPTIBLE_APP_ADJ(200).
  • The UI process is separated from the Service process, and when the app switches to the background, the unseparated Service process (app process) is degraded toCACHED_APP_MIN_ADJ(900), while the Service process with process separation is always kept asSERVICE_ADJ(500).
  • Memory optimization: For processes of the same level with the same ADJ value, the system will reclaim the APP processes that occupy the most memory.

summary

Back to the original question: Was the Activity reclaimed by the system? Is it only possible that the entire APP process is recycled by the system? In fact, it is not. We know that Android system allocates a memory limit for each app process. When the app uses more memory than this limit, an OOM exception will occur. For this scenario, the Android system has also developed some mechanisms to recycle the Activity stack. In simple terms:

In the case of single-stack (TaskRecord) applications, none of the interfaces are reclaimed in the foreground, and only activities with invisible stacks are reclaimed in multi-stack cases.

For details, see the TaskRecord destruction analysis in the Android Visible APP.

Reference article:

  • Read the Android process priority adj. algorithm
  • The App is in the foreground, so the Activity is not recycled?
  • TaskRecord destruction analysis for Android Visible APP
  • Android memory reclamation mechanism
  • Android Developers process and application lifecycle
  • Memory allocation between Android Developers processes