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 screen
Activity
(theonResume()
Method already called). - It has one
BroadcastReceiver
Currently running (itsBroadcastReceiver.onReceive()
Method executing). - It has one
Service
Currently executing one of its callbacks (Service.onCreate()
,Service.onStart()
或Service.onDestroy()
).
- It’s running one on the user’s interactive screen
- 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 running
Activity
Visible 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 one
Service
Is 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.
- It’s running
- Service process —
IMPORTANCE_SERVICE
- Contains one already in use
startService()
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.
- Contains one already in use
- Background process —
IMPORTANCE_BACKGROUND
- Apps switch to the background, and apps usually contain one or more that are not currently visible to the user
Activity
Instance (onStop()
Method has been called and returned).
- Apps switch to the background, and apps usually contain one or more that are not currently visible to the user
- 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 to
IMPORTANCE_BACKGROUND
- Is equivalent to
- For Android 11.0, there are nine
IMPORTANCE_TOP_SLEEPING
- Foreground APP, but the system entered hibernation, this APP process.
IMPORTANCE_FOREGROUND_SERVICE
- will
Service.startForeground()
The front desk service has been split, single column.
- will
-
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 screen
Activity
(theonResume()
Method already called). - It has one
BroadcastReceiver
Currently running (itsBroadcastReceiver.onReceive()
Method executing). - It has one
Service
Currently executing one of its callbacks (Service.onCreate()
,Service.onStart()
或Service.onDestroy()
).
VISIBLE_APP_ADJ, adj = 100
Service. StartForeground () foreground Service
- It’s running
Activity
Visible 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 user
Activity
Instance (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 highest
oom_adj_score
The 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 circumstances
android: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 service
Service.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 to
CACHED_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