湖南網站建設kaodezhu百度客服電話24小時人工服務熱線
該系列文章總綱鏈接:專題總綱目錄 Android Framework 總綱
本章關鍵點總結 & 說明:
說明:本章節(jié)主要解讀AMS 進程方面的知識。關注思維導圖中左上側部分即可。
我們本章節(jié)主要是對Android進程管理相關知識有一個基本的了解。先來了解下Linux的進程管理,基于此,我們再談Android的進程管理體系。最后了解AMS中2個關鍵的進程管理API:updateLruProcessLocked 和 updateOomAdjLocked。
1 Linux的進程管理
Linux的進程調度是操作系統(tǒng)核心功能之一,它負責決定哪個進程在何時運行以及運行多長時間。以下是Linux進程調度的基本機制,以及setpriority
和sched_setscheduler
兩個方法的詳細解讀。
1.1 Linux進程調度簡要解讀
Linux進程調度基本機制解讀如下
- ?調度器(Scheduler):Linux使用調度器來決定進程的執(zhí)行順序。調度器根據進程的優(yōu)先級和調度策略來選擇下一個要執(zhí)行的進程。
- 調度策略(Scheduling Policies):Linux支持多種調度策略,包括
SCHED_NORMAL
(普通)、SCHED_FIFO
(先進先出)、SCHED_RR
(時間片輪轉)、SCHED_BATCH
(批處理)和SCHED_IDLE
(空閑)等。 - 優(yōu)先級(Priority):每個調度策略都有自己的優(yōu)先級范圍。進程的優(yōu)先級越低(數值越小),它被調度執(zhí)行的優(yōu)先級就越高。
- 時間片(Time Slice):在
SCHED_RR
和SCHED_NORMAL
策略下,進程被分配一個時間片,即它在被搶占前可以運行的時間。 - 上下文切換(Context Switching):當一個進程的時間片用完或者它主動放棄CPU時,會發(fā)生上下文切換,調度器會選擇另一個進程來執(zhí)行。
?1.2 setpriority 系統(tǒng)調用
setpriority
系統(tǒng)調用用于設置進程的靜態(tài)優(yōu)先級。這個優(yōu)先級是在進程創(chuàng)建時分配的,并且通常不會改變,除非顯式地調用setpriority
。API詳細解讀如下:
int setpriority(int which, int who, int value);
hich
:指定要設置的優(yōu)先級類型,可以是PRIO_PROCESS
(進程)、PRIO_PGRP
(進程組)或PRIO_USER
(用戶)。who
:指定要設置優(yōu)先級的進程ID、進程組ID或用戶ID。value
:指定新的優(yōu)先級值,值越小優(yōu)先級越高。
接下來我們來看看setpriority具體的使用方法,demo如下:
#include <sys/resource.h>
#include <stdio.h>int main() {// 設置當前進程的nice值,值越小優(yōu)先級越高int result = setpriority(PRIO_PROCESS, getpid(), -10);if (result == -1) {perror("setpriority");return 1;}printf("Priority set to: %d\n", getpriority(PRIO_PROCESS, getpid()));return 0;
}
這個程序將當前進程的nice值設置為-10,這通常會提高進程的優(yōu)先級。getpriority
函數用于獲取當前進程的優(yōu)先級,以驗證setpriority
是否成功。
1.3 sched_setscheduler 系統(tǒng)調用
sched_setscheduler
系統(tǒng)調用用于設置進程的動態(tài)調度策略和相關參數。API詳細解讀如下:
struct sched_param {int sched_priority; /* Process execution priority */
};int sched_setscheduler(pid_t pid, const struct sched_param *param);
pid
:指定要設置調度策略的進程ID。如果pid
是0,則設置調用進程的調度策略。param
:指向sched_param
結構的指針,該結構包含了新的調度參數,如優(yōu)先級。
接下來我們來看看sched_setscheduler具體的使用方法,demo如下:
#include <sched.h>
#include <stdio.h>
#include <unistd.h>int main() {// 定義調度參數結構體struct sched_param param;param.sched_priority = 1; // 設置優(yōu)先級為1// 設置調度策略為SCHED_FIFOint policy = SCHED_FIFO;int result = sched_setscheduler(0, policy, ¶m);if (result == -1) {perror("sched_setscheduler");return 1;}printf("Scheduler set to: %d\n", policy);printf("Priority set to: %d\n", param.sched_priority);// 讓進程睡眠一段時間,以便觀察調度效果sleep(10);return 0;
}
這個程序將當前進程的調度策略設置為SCHED_FIFO
,并設置優(yōu)先級為1。sched_setscheduler
函數的第一個參數是0,表示設置調用進程的調度策略。policy
變量指定了新的調度策略,param
結構體指定了調度參數。
注意事項解讀:
- 在使用
sched_setscheduler
時,需要確保進程有適當的權限(通常是root權限),因為改變進程的調度策略可能需要管理員權限。 setpriority
和sched_setscheduler
的使用可能會受到操作系統(tǒng)安全策略的限制,特別是在生產環(huán)境中。- 這些調用的行為可能會因不同的Linux發(fā)行版和內核配置而異。
總結:setpriority
和sched_setscheduler
是Linux進程調度中兩個重要的系統(tǒng)調用。setpriority
用于設置進程的靜態(tài)優(yōu)先級,而sched_setscheduler
用于設置進程的動態(tài)調度策略和優(yōu)先級。這兩個調用共同決定了進程的調度行為,允許操作系統(tǒng)和應用程序精細控制進程的執(zhí)行順序和優(yōu)先級。通過合理配置這些參數,可以優(yōu)化系統(tǒng)性能,確保關鍵任務的及時響應。
2 Android進程解讀
2.1 Android進程分類
Android進程管理和Linux進程管理之間的關系是密切的,因為Android系統(tǒng)是建立在Linux內核之上的。在Android中,進程的分類和管理與Linux中有許多相似之處,但也做了一些特定的優(yōu)化和擴展以適應移動設備的特點。以下是Android進程分類的核心調用和它們與Linux進程管理的對應關系:
- 前臺進程(Foreground Processes):在Linux中,前臺進程通常是指那些與用戶直接交互的進程。在Android中,前臺進程包括正在運行的Activity和正在執(zhí)行的BroadcastReceiver。這些進程因為與用戶直接交互,所以系統(tǒng)會優(yōu)先保持它們的運行。
- 可見進程(Visible Processes):可見進程在Android中是指那些對用戶可見但不在前臺的進程,例如用戶最近查看的Activity。Linux中沒有直接對應的概念,但可以通過進程的可見性來進行類比。
- 服務進程(Service Processes):在Android中,服務進程是指那些運行Service組件的進程。這些服務可能在后臺執(zhí)行任務,但對應用程序的行為至關重要。Linux中,服務通常作為守護進程運行,與Android中的服務進程概念相似。
- 后臺進程(Background Processes):后臺進程在Android中是指那些對用戶不可見的Activity所在的進程。這些進程可能會被系統(tǒng)根據需要終止以釋放內存。在Linux中,后臺進程通常是指那些在后臺運行的進程,如守護進程。
- 空進程(Empty Processes):空進程在Android中是指那些不包含任何活躍組件的進程,但可能因為某些原因(如服務綁定)而保留在內存中。Linux中沒有直接對應的概念,但可以通過進程的資源占用來進行類比。
在Android中,進程的創(chuàng)建和管理是通過ActivityManagerService來協(xié)調的,而在Linux中,進程的創(chuàng)建和管理是通過內核的調度器和系統(tǒng)調用(如fork、exec、exit)來實現(xiàn)的。Android在Linux的基礎上增加了一些特定的管理機制,如進程的分類和優(yōu)先級管理,以及與應用程序組件生命周期相關的進程管理策略。這些機制使得Android能夠有效地管理有限的資源,并提供良好的用戶體驗。
2.2 進程調度相關API
在Android Framework中,Process.java
文件提供了多個與進程調度相關的API。以下是一些最關鍵的API:
public class Process {private static final String LOG_TAG = "Process";//.../*** 設置當前線程的優(yōu)先級。* * @param priority 要設置的優(yōu)先級值,值越小優(yōu)先級越高。* @throws IllegalArgumentException 如果優(yōu)先級值不在合法范圍內。* @throws SecurityException 如果當前進程沒有權限設置線程優(yōu)先級。*/public static final native void setThreadPriority(int priority)throws IllegalArgumentException, SecurityException;/*** 設置指定線程的優(yōu)先級。* * @param tid 目標線程的ID。* @param priority 要設置的優(yōu)先級值,值越小優(yōu)先級越高。* @throws IllegalArgumentException 如果優(yōu)先級值不在合法范圍內或線程ID無效。* @throws SecurityException 如果當前進程沒有權限設置指定線程的優(yōu)先級。*/public static final native void setThreadPriority(int tid, int priority)throws IllegalArgumentException, SecurityException;/*** 獲取指定線程的優(yōu)先級。* * @param tid 目標線程的ID。* @return 線程的當前優(yōu)先級值。* @throws IllegalArgumentException 如果線程ID無效。*/public static final native int getThreadPriority(int tid)throws IllegalArgumentException;/*** 將線程分組到一個線程組。* * @param tid 目標線程的ID。* @param group 線程組的ID。* @throws IllegalArgumentException 如果線程ID或線程組ID無效。* @throws SecurityException 如果當前進程沒有權限更改線程組。*/public static final native void setThreadGroup(int tid, int group)throws IllegalArgumentException, SecurityException;/*** 將進程分組到一個進程組。* * @param pid 目標進程的ID。* @param group 進程組的ID。* @throws IllegalArgumentException 如果進程ID或進程組ID無效。* @throws SecurityException 如果當前進程沒有權限更改進程組。*/public static final native void setProcessGroup(int pid, int group)throws IllegalArgumentException, SecurityException;/*** 獲取進程所在的進程組ID。* * @param pid 目標進程的ID。* @return 進程所在的進程組ID。* @throws IllegalArgumentException 如果進程ID無效。*/public static final native int getProcessGroup(int pid)throws IllegalArgumentException;//...
}
這些native方法提供了對Android進程和線程調度參數的控制,它們通過JNI(Java Native Interface)與底層的C/C++代碼交互,最終調用Linux內核的系統(tǒng)調用來實現(xiàn)具體的調度策略。API解讀如下:
- setThreadPriority(int priority):這個方法用于設置當前線程的優(yōu)先級。在Android中,線程優(yōu)先級的范圍通常是-20(最高)到19(最低)。
- setThreadPriority(int tid, int priority):這個方法用于設置指定線程的優(yōu)先級。
tid
參數指定了目標線程的ID。 - getThreadPriority(int tid):這個方法用于獲取指定線程的優(yōu)先級。
tid
參數指定了目標線程的ID。 - setThreadGroup(int tid, int group):這個方法用于將線程分組到一個線程組。在Linux中,線程組通常用于調度和資源管理。
- setProcessGroup(int pid, int group):這個方法用于將進程分組到一個進程組。在Linux中,進程組通常用于調度和資源管理。
- getProcessGroup(int pid):這個方法用于獲取進程所在的進程組ID。
pid
參數指定了目標進程的ID。
這些方法的使用需要相應的權限,特別是在修改其他進程的調度策略時,通常需要系統(tǒng)權限或者root權限。通過合理使用這些API,開發(fā)者可以優(yōu)化應用的性能和響應速度,或者在特定場景下對系統(tǒng)資源進行更精細的控制。
2.3 Android進程關鍵變量解讀
在Android系統(tǒng)中,OOM_ADJ和LRU是兩個關鍵的進程管理參數,因為它們共同決定了Android系統(tǒng)中進程的內存分配和回收策略,具體如下:
- 內存管理:OOM_ADJ和LRU幫助系統(tǒng)在內存不足時決定哪些進程可以被犧牲以釋放內存資源。這對于保持系統(tǒng)穩(wěn)定性和響應性至關重要,尤其是在內存資源有限的移動設備上。
- 進程優(yōu)先級:通過調整OOM_ADJ值,系統(tǒng)可以為不同類型的進程設置不同的優(yōu)先級,確保關鍵任務(如前臺應用)獲得足夠的資源,而后臺或不常用的進程則可以被適當地犧牲。
- 性能優(yōu)化:合理使用LRU和OOM_ADJ可以提高應用的啟動速度和響應性,因為系統(tǒng)可以更快地從緩存中恢復進程,而不是每次都從頭開始啟動進程。
- 資源平衡:這兩個參數使得系統(tǒng)能夠在保證用戶體驗的同時,合理分配有限的資源,平衡不同應用和進程的需求。
可見,它們直接影響系統(tǒng)的內存管理和進程調度策略,對于優(yōu)化系統(tǒng)性能和用戶體驗具有重要意義。
2.3.1 OOM_ADJ的解讀
OOM_ADJ(Out-Of-Memory Adjustment):OOM_ADJ值是一個整數,用來表示進程的優(yōu)先級,特別是在系統(tǒng)內存不足時決定哪些進程可以被殺死以回收內存。OOM_ADJ值的設計目的和設計意義如下:
- 設計目的:OOM_ADJ值的主要目的是為了在系統(tǒng)內存不足時,能夠根據進程的重要性進行合理的內存回收。系統(tǒng)會優(yōu)先殺死那些對用戶體驗影響較小的進程,保護前臺進程和對用戶體驗至關重要的后臺進程。
- 設計意義:OOM_ADJ值有助于提高Android設備的用戶體驗和系統(tǒng)穩(wěn)定性。它允許系統(tǒng)在面臨內存壓力時,根據進程的重要性做出合理的決策,從而在保證用戶體驗的同時,也確保系統(tǒng)的流暢運行。
在Android中,OOM_ADJ值的范圍通常是從-1000到1000,其中-1000表示最高優(yōu)先級(最不容易被殺死),而1000表示最低優(yōu)先級(最容易被殺死)。OOM_ADJ的值定義在ProcessList.java中,代碼實現(xiàn)如下:
final class ProcessList {// 應用崩潰間隔的最短時間,用于判斷應用是否不穩(wěn)定,如果是,則停止其服務并拒絕廣播。static final int MIN_CRASH_INTERVAL = 60 * 1000;// 處于不同狀態(tài)的進程的OOM(Out Of Memory)調整值:// 在某些地方使用,我們還不確定具體的值。// (通常是要被緩存的值,但我們還不知道緩存范圍中的確切值。)static final int UNKNOWN_ADJ = 16;// 只托管不可見活動的進程,可以在不造成任何干擾的情況下殺死。static final int CACHED_APP_MAX_ADJ = 15;static final int CACHED_APP_MIN_ADJ = 9;// 服務B列表的調整值——這些是舊的、不受歡迎的服務,不像A列表中的服務那樣吸引人。static final int SERVICE_B_ADJ = 8;// 這是用戶之前所在的應用進程。這個進程被保持在較高優(yōu)先級,因為用戶經常會切換回之前的應用。// 這對于最近任務切換(在兩個最近的應用程序之間切換)和正常UI流程(例如,在電子郵件應用中點擊一個URI在瀏覽器中查看,然后按返回鍵回到電子郵件)都很重要。static final int PREVIOUS_APP_ADJ = 7;// 這是托管Home應用的進程——我們希望盡量避免殺死它,即使它通常在后臺,因為用戶與之交互很多。static final int HOME_APP_ADJ = 6;// 這是托管應用服務的進程——殺死它對用戶的影響不大。static final int SERVICE_ADJ = 5;// 這是一個托管重量級應用的進程。它在后臺,但我們希望盡量避免殺死它。值在系統(tǒng)啟動時在system/rootdir/init.rc中設置。static final int HEAVY_WEIGHT_APP_ADJ = 4;// 這是一個當前托管備份操作的進程。殺死它不是完全致命的,但通常是一個壞主意。static final int BACKUP_APP_ADJ = 3;// 這是一個只托管對用戶可感知的組件的進程,我們真的希望避免殺死它們,但它們不是立即可見的。一個例子是后臺音樂播放。static final int PERCEPTIBLE_APP_ADJ = 2;// 這是一個只托管對用戶可見的活動的進程,所以我們希望它們不要消失。static final int VISIBLE_APP_ADJ = 1;// 這是運行當前前臺應用的進程。我們真的不想殺死它!static final int FOREGROUND_APP_ADJ = 0;// 這個進程被系統(tǒng)或持久進程綁定,并表示它很重要。static final int PERSISTENT_SERVICE_ADJ = -11;// 這是一個系統(tǒng)持久進程,如電話進程。肯定不想殺死它,但如果這樣做了,也不是完全致命的。static final int PERSISTENT_PROC_ADJ = -12;// 系統(tǒng)進程以默認的調整值運行。static final int SYSTEM_ADJ = -16;// 特殊代碼,用于沒有被系統(tǒng)管理的本地進程(所以沒有被系統(tǒng)分配oom調整值)。static final int NATIVE_ADJ = -17;//...// 這些是我們要提供給OOM killer的各種內存級別。// 注意OOM killer只支持6個插槽,所以我們不能為每種可能的進程類型提供不同的值。private final int[] mOomAdj = new int[] {FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ};// 這些是低端OOM級別限制。這適用于HVGA或更小屏幕的手機,內存少于512MB。// 值以KB為單位。private final int[] mOomMinFreeLow = new int[] {12288, 18432, 24576,36864, 43008, 49152};// 這些是高端OOM級別限制。這適用于1280x800或更大屏幕,大約有1GB RAM。// 值以KB為單位。private final int[] mOomMinFreeHigh = new int[] {73728, 92160, 110592,129024, 147456, 184320};
}
這些常量代表了Android系統(tǒng)中不同類型進程的OOM(內存不足時的殺進程)調整值。這些值用于確定進程被系統(tǒng)殺死的優(yōu)先級,值越小表示優(yōu)先級越高,越不容易被系統(tǒng)殺死。這些調整值幫助系統(tǒng)在內存不足時決定哪些進程可以被犧牲以釋放內存。用于更新oom_adj的方法為updateOomAdjLocked。
2.3.2 LRU相關變量解讀
LRU(Least Recently Used):LRU是最近最少使用算法,核心思想是當緩存滿時,優(yōu)先淘汰那些近期最少使用的緩存對象(如果一個數據最近被訪問過,那么它在未來被訪問的概率更高;相反,如果一個數據長時間未被訪問,那么它在未來被訪問的概率較低),有效避免了OOM的出現(xiàn)。
lruWeight是一個用于衡量進程在最近最少使用(LRU)列表中排序權重的參數。它通常與進程的最后活動時間或其他活動相關的因素相關聯(lián),用于確定進程在LRU列表中的位置。lruWeight值的設計目的和設計意義如下:
- 設計目的:lruWeight的設計目的是為了在系統(tǒng)內存不足時,根據進程的最近使用情況來決定哪些進程可以被優(yōu)先殺死以釋放內存。它幫助系統(tǒng)維護一個有序的進程列表,確保最近被使用的進程保持在內存中,而長時間未被使用的進程則可以被犧牲。
- 設計意義:lruWeight的設計意義在于優(yōu)化內存資源的分配和回收。通過動態(tài)調整進程的lruWeight值,系統(tǒng)能夠更智能地管理內存,提高內存使用效率。這不僅有助于提升用戶體驗,比如通過快速恢復最近使用的應用程序,還能在內存緊張時減少系統(tǒng)的卡頓或崩潰。
lruWeight與OOM調整值的關系:lruWeight與進程的OOM調整值(OOM_ADJ)緊密相關,因為它們共同決定了進程在內存不足時的生存概率。一個進程的lruWeight值越高,其OOM調整值可能越低,表示它越容易被系統(tǒng)殺死。
此外,lruWeight還考慮了進程的類型和服務狀態(tài),比如活動、服務和內容提供者,這使得系統(tǒng)能夠根據進程的實際作用和重要性來調整其在LRU列表中的位置,進一步優(yōu)化內存管理。
lruWeight是Android系統(tǒng)中一個關鍵的內存管理參數,它通過反映進程的活躍度和重要性來幫助系統(tǒng)在有限的資源下做出合理的內存分配和回收決策。在Android中,LRU算法常用于內存緩存和硬盤緩存的管理。用于更新LRU的方法為updateLruProcessLocked。
3 AMS 進程管理相關函數分析
基于OOM_ADJ和LRU是兩個關鍵的進程管理參數,這里我們主要探討更新OOM_ADJ和LRU的方法。這里以startProcessLocked
方法啟動一個新進程為例,啟動相關的代碼可參考文章:
Android Framework AMS(04)startActivity分析-1(am啟動到ActivityThread啟動)
Android Framework AMS(05)startActivity分析-2(ActivityThread啟動到Activity拉起)
這里我們主要從AMS的attachApplicationLocked方法入手進行分析。代碼實現(xiàn)如下:
//AMSprivate final boolean attachApplicationLocked(IApplicationThread thread,int pid) {ProcessRecord app;//...try {//...// 將應用程序線程與應用程序信息綁定thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,isRestrictedBackupMode || !normalMode, app.persistent,new Configuration(mConfiguration), app.compat,getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked());// 更新進程的LRU列表updateLruProcessLocked(app, false, null);//...} catch (Exception e) {//...}// 如果沒有執(zhí)行任何操作,則更新OOM調整值if (!didSomething) {updateOomAdjLocked();}return true;}
這里開始就已經調用了2個重要函數updateLruProcessLocked和updateOomAdjLocked。接下來對這2個方法進行更詳細的解讀。
3.1 updateLruProcessLocked分析
updateLruProcessLocked的代碼實現(xiàn),如下所示:
//AMSfinal void updateLruProcessLocked(ProcessRecord app, boolean activityChange,ProcessRecord client) {// 檢查進程是否有activityfinal boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities|| app.treatLikeActivity;// 檢查進程是否有服務final boolean hasService = false;// 如果沒有activity變化且進程有activity,則直接返回if (!activityChange && hasActivity) {return;}// 更新LRU序列號mLruSeq++;final long now = SystemClock.uptimeMillis(); // 獲取當前時間app.lastActivityTime = now; // 更新進程的最后activity時間// 如果進程有activity,檢查它是否已經在LRU列表的最后if (hasActivity) {final int N = mLruProcesses.size();if (N > 0 && mLruProcesses.get(N - 1) == app) {return; // 如果進程已經是最后一個,直接返回}} else {// 如果進程沒有activity,檢查它是否在服務啟動列表中if (mLruProcessServiceStart > 0&& mLruProcesses.get(mLruProcessServiceStart - 1) == app) {return; // 如果進程在服務啟動列表中,直接返回}}// 查找進程在LRU列表中的索引int lrui = mLruProcesses.lastIndexOf(app);//...// 如果進程在LRU列表中,移除它if (lrui >= 0) {if (lrui < mLruProcessActivityStart) {mLruProcessActivityStart--; // 更新activity進程起始索引}if (lrui < mLruProcessServiceStart) {mLruProcessServiceStart--; // 更新服務進程起始索引}mLruProcesses.remove(lrui); // 從LRU列表中移除進程}int nextIndex;// 如果進程有activity,添加到LRU列表if (hasActivity) {final int N = mLruProcesses.size();if (app.activities.size() == 0 && mLruProcessActivityStart < (N - 1)) {mLruProcesses.add(N - 1, app); // 將進程添加到LRU列表的倒數第二個位置final int uid = app.info.uid;for (int i = N - 2; i > mLruProcessActivityStart; i--) {ProcessRecord subProc = mLruProcesses.get(i);if (subProc.info.uid == uid) {if (mLruProcesses.get(i - 1).info.uid != uid) {// 交換進程位置ProcessRecord tmp = mLruProcesses.get(i);mLruProcesses.set(i, mLruProcesses.get(i - 1));mLruProcesses.set(i - 1, tmp);i--;}} else {break; // 如果UID不同,停止交換}}} else {mLruProcesses.add(app); // 直接添加進程到LRU列表}nextIndex = mLruProcessServiceStart; // 設置下一個索引} else if (hasService) {// 如果進程有service,添加到LRU列表的activity起始位置mLruProcesses.add(mLruProcessActivityStart, app);nextIndex = mLruProcessServiceStart;mLruProcessActivityStart++;} else {// 處理沒有activity和service的進程int index = mLruProcessServiceStart;if (client != null) {int clientIndex = mLruProcesses.lastIndexOf(client);if (clientIndex <= lrui) {clientIndex = lrui; // 確保clientIndex不小于lrui}if (clientIndex >= 0 && index > clientIndex) {index = clientIndex; // 更新索引}}mLruProcesses.add(index, app); // 在指定索引添加進程nextIndex = index - 1; // 更新下一個索引mLruProcessActivityStart++;mLruProcessServiceStart++;}// 更新與進程連接的服務的LRU狀態(tài)for (int j = app.connections.size() - 1; j >= 0; j--) {ConnectionRecord cr = app.connections.valueAt(j);if (cr.binding != null && !cr.serviceDead && cr.binding.service != null&& cr.binding.service.app != null&& cr.binding.service.app.lruSeq != mLruSeq&& !cr.binding.service.app.persistent) {nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex,"service connection", cr, app);}}// 更新與進程相關的內容提供者的LRU狀態(tài)for (int j = app.conProviders.size() - 1; j >= 0; j--) {ContentProviderRecord cpr = app.conProviders.get(j).provider;if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.persistent) {nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,"provider reference", cpr, app);}}}
updateLruProcessLocked方法的主要目的是更新特定進程在LRU列表中的位置,基于進程的活動狀態(tài)(如是否有活動或服務)。如果進程有活動(Activity),則不會移動該進程在LRU列表中的位置,因為活動進程應該被優(yōu)先保留。如果進程沒有活動,但有服務連接或內容提供者引用,該方法會調整這些進程在LRU列表中的位置,以反映它們的使用情況。通過mLruSeq序列號控制更新,確保只有在進程狀態(tài)發(fā)生變化時才進行更新,減少不必要的列表操作。
在updateLruProcessLocked方法中,調整的具體是mLruProcesses這個關鍵變量。mLruProcesses是一個列表,它存儲了系統(tǒng)中所有進程的最近最少使用(LRU)順序。以下是對這個方法中涉及的關鍵變量和操作的分析:
- mLruProcesses:這是一個列表,包含了系統(tǒng)中所有進程的ProcessRecord對象,按照它們的最近使用情況排序。列表的前端(即索引較小的位置)存放最近使用的進程,而列表的后端(即索引較大的位置)存放最少使用的進程。
- app.lastActivityTime:每個ProcessRecord對象中的lastActivityTime字段被更新為當前時間,這表示進程最后一次活躍的時間。這個字段用于確定進程在LRU列表中的位置。
- mLruProcessActivityStart和mLruProcessServiceStart:這兩個變量分別標記了LRU列表中活動進程和服務進程的起始索引。它們用于區(qū)分不同類型的進程,并在添加進程到LRU列表時確定正確的位置。
- mLruSeq:mLruSeq是一個序列號,每次調用updateLruProcessLocked方法時增加,用于標識LRU列表的更新周期。
在方法中執(zhí)行的操作包括:
- 更新進程的最后活動時間:通過設置app.lastActivityTime為當前時間來更新。
- 檢查進程是否有活動:如果進程有活動(hasActivity),并且沒有活動變化(!activityChange),則不進行進一步操作。
- 移除和添加進程:如果進程在LRU列表中的位置發(fā)生變化,它會從當前位置移除,并根據其活動狀態(tài)被重新添加到LRU列表的適當位置。
- 更新服務和內容提供者的LRU狀態(tài):對于與進程連接的服務和內容提供者,它們在LRU列表中的位置也可能需要更新,這是通過調用updateLruProcessInternalLocked方法實現(xiàn)的。
總結來說,updateLruProcessLocked方法通過直接操作mLruProcesses列表和相關索引變量來管理進程的LRU順序,確保列表反映了進程的最新使用情況。這種方法有助于系統(tǒng)在內存不足時決定哪些進程可以被優(yōu)先殺死。
這里最后在處理service和ContentProcider時調用了updateLruProcessInternalLocked方法,它的代碼實現(xiàn)如下所示:
//AMSprivate int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,String what, Object obj, ProcessRecord srcApp) {// 更新進程的最后活動時間app.lastActivityTime = now;// 如果進程有活動,不更新其在LRU列表中的位置if (app.activities.size() > 0) {return index; // 不處理包含活動的進程}// 查找進程在LRU列表中的索引int lrui = mLruProcesses.lastIndexOf(app);// 如果進程不在LRU列表中,記錄錯誤并返回if (lrui < 0) {return index;}// 如果進程在LRU列表中的位置已經小于或等于目標索引,不更新位置if (lrui >= index) {return index; // 不使依賴進程在列表中向后移動}// 如果進程在活動進程的起始索引之后,不更新其位置if (lrui >= mLruProcessActivityStart) {return index; // 不處理包含活動的進程}// 從當前位置移除進程mLruProcesses.remove(lrui);// 如果目標索引大于0,將其減1if (index > 0) {index--;}// 在目標索引位置添加進程mLruProcesses.add(index, app);// 返回更新后的目標索引return index;}
updateLruProcessInternalLocked方法用于在LRU列表中移動依賴進程(即那些沒有直接用戶交互,但被其他進程依賴的進程)。如果依賴進程沒有活動,并且不在活動進程的起始索引之后,該方法會將這些進程向前移動,以確保它們不會被錯誤地視為最近最少使用的進程。該方法確保依賴進程不會移動到活動進程之后,從而避免降低它們的優(yōu)先級。如果依賴進程不在LRU列表中,該方法會記錄錯誤并保持列表不變。
總體來說,updateLruProcessLocked負責處理進程的直接狀態(tài)變化,而updateLruProcessInternalLocked負責處理由這些變化引起的依賴進程的間接影響。通過精確控制進程在LRU列表中的位置,這兩個方法幫助系統(tǒng)優(yōu)化內存管理,確保在內存不足時能夠優(yōu)先殺死那些最近最少使用的進程,同時保護前臺進程和關鍵后臺進程。
3.2 updateOomAdjLocked分析
updateOomAdjLocked的代碼較長,這里分成2個部分進行解讀。
3.2.1 updateOomAdjLocked前半段代碼解讀
updateOomAdjLocked前半段代碼實現(xiàn)如下所示:
final void updateOomAdjLocked() {// 獲取當前前臺活動的Activity和對應的進程記錄final ActivityRecord TOP_ACT = resumedAppLocked();final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;// 獲取當前時間,用于計算時間差final long now = SystemClock.uptimeMillis();// 計算30分鐘前的時間,用于判斷進程是否為空final long oldTime = now - ProcessList.MAX_EMPTY_TIME;// 獲取LRU列表中的進程數量final int N = mLruProcesses.size();// 增加OOM調整值的序列號,用于標識調整周期mAdjSeq++;// 初始化服務進程的數量mNewNumServiceProcs = 0;mNewNumAServiceProcs = 0;// 根據系統(tǒng)配置計算空進程和緩存進程的最大數量final int emptyProcessLimit;final int cachedProcessLimit;if (mProcessLimit <= 0) {emptyProcessLimit = cachedProcessLimit = 0;} else if (mProcessLimit == 1) {emptyProcessLimit = 1;cachedProcessLimit = 0;} else {emptyProcessLimit = ProcessList.computeEmptyProcessLimit(mProcessLimit);cachedProcessLimit = mProcessLimit - emptyProcessLimit;}// 計算緩存進程的調整值步長int numSlots = (ProcessList.CACHED_APP_MAX_ADJ- ProcessList.CACHED_APP_MIN_ADJ + 1) / 2;// 計算空進程的數量int numEmptyProcs = N - mNumNonCachedProcs - mNumCachedHiddenProcs;if (numEmptyProcs > cachedProcessLimit) {numEmptyProcs = cachedProcessLimit;}// 計算空進程和緩存進程的調整值步長因子int emptyFactor = numEmptyProcs / numSlots;if (emptyFactor < 1) emptyFactor = 1;int cachedFactor = (mNumCachedHiddenProcs > 0 ? mNumCachedHiddenProcs : 1) / numSlots;if (cachedFactor < 1) cachedFactor = 1;// 初始化步長計數器int stepCached = 0;int stepEmpty = 0;// 初始化緩存和空進程的數量計數器int numCached = 0;int numEmpty = 0;int numTrimming = 0;// 初始化非緩存進程和緩存隱藏進程的數量計數器mNumNonCachedProcs = 0;mNumCachedHiddenProcs = 0;// 初始化緩存和空進程的OOM調整值int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ;int nextCachedAdj = curCachedAdj + 1;int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;int nextEmptyAdj = curEmptyAdj + 2;// 遍歷LRU列表,更新每個進程的OOM調整值for (int i = N - 1; i >= 0; i--) {ProcessRecord app = mLruProcesses.get(i);// 如果進程沒有被殺死并且有線程,更新其OOM調整值if (!app.killedByAm && app.thread != null) {app.procStateChanged = false;// 計算進程的OOM調整值computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {// 根據進程狀態(tài)調整OOM值switch (app.curProcState) {case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:app.curRawAdj = curCachedAdj;app.curAdj = app.modifyRawOomAdj(curCachedAdj);if (curCachedAdj != nextCachedAdj) {stepCached++;if (stepCached >= cachedFactor) {stepCached = 0;curCachedAdj = nextCachedAdj;nextCachedAdj += 2;if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) {nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ;}}}break;default:app.curRawAdj = curEmptyAdj;app.curAdj = app.modifyRawOomAdj(curEmptyAdj);if (curEmptyAdj != nextEmptyAdj) {stepEmpty++;if (stepEmpty >= emptyFactor) {stepEmpty = 0;curEmptyAdj = nextEmptyAdj;nextEmptyAdj += 2;if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) {nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ;}}}break;}}// 應用OOM調整值applyOomAdjLocked(app, TOP_APP, true, now);// 根據進程類型計數switch (app.curProcState) {case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:mNumCachedHiddenProcs++;numCached++;if (numCached > cachedProcessLimit) {app.kill("cached #" + numCached, true);}break;case ActivityManager.PROCESS_STATE_CACHED_EMPTY:if (numEmpty > ProcessList.TRIM_EMPTY_APPS&& app.lastActivityTime < oldTime) {app.kill("empty for " + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime) / 1000) + "s", true);} else {numEmpty++;if (numEmpty > emptyProcessLimit) {app.kill("empty #" + numEmpty, true);}}break;default:mNumNonCachedProcs++;break;}// 殺死孤立的進程if (app.isolated && app.services.size() <= 0) {app.kill("isolated not needed", true);}// 計算需要調整的進程數量if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME&& !app.killedByAm) {numTrimming++;}}}//...}
updateOomAdjLocked方法的前半部分主要負責初始化OOM調整值的計算環(huán)境,包括確定進程的OOM調整值序列、計算空進程和緩存進程的限制數量、以及遍歷LRU列表更新每個進程的OOM調整值。這一部分還涉及到根據進程的活動狀態(tài)(如前臺活動、服務狀態(tài)等)來調整其在LRU列表中的位置,并決定是否需要殺死超出內存限制的進程。
同時我們這里關注兩個關鍵方法:computeOomAdjLocked和applyOomAdjLocked:
@1 computeOomAdjLocked方法
computeOomAdjLocked方法用于計算進程的OOM調整值,在android的各個版本中該方法差異較大,但核心功能和設計目的不變,核心功能和設計目的解讀如下:
- 動態(tài)調整OOM值:
computeOomAdjLocked
方法根據進程的活動狀態(tài)(如前臺活動、服務狀態(tài)等)來計算其OOM值。這個值決定了進程在系統(tǒng)內存不足時被回收的可能性,值越高表示進程越不可能被殺死。 - 進程優(yōu)先級管理:方法通過評估進程的重要性來調整其優(yōu)先級,確保在內存緊張時,前臺進程和關鍵后臺進程能夠獲得更多的保護,而后臺或不活躍的進程則更容易被犧牲以釋放內存。
- 響應系統(tǒng)狀態(tài)變化:當Android四大組件(Activity、Service、Broadcast Receiver、Content Provider)的狀態(tài)發(fā)生變化時,該方法會被調用來更新相應進程的OOM值,以反映這些變化對進程優(yōu)先級的影響。
- 優(yōu)化內存使用:設計目的是在保證用戶體驗的同時,合理利用系統(tǒng)資源。通過對進程OOM值的動態(tài)管理,系統(tǒng)能夠在內存緊張時優(yōu)先保留用戶最可能需要的進程,同時釋放那些對用戶體驗影響較小的進程所占用的內存。
- 系統(tǒng)穩(wěn)定性和響應性:通過合理分配內存資源,
computeOomAdjLocked
方法有助于提高系統(tǒng)的穩(wěn)定性和響應性。它確保了在內存不足的情況下,系統(tǒng)能夠做出合理的決策,避免因內存不足導致的系統(tǒng)崩潰或應用異常。
computeOomAdjLocked方法是Android系統(tǒng)中一個重要的內存管理機制,它通過動態(tài)調整進程的OOM值來優(yōu)化內存使用,保護關鍵進程,并在內存緊張時做出合理的內存回收決策。
@2 applyOomAdjLocked方法
applyOomAdjLocked方法主要根據進程的狀態(tài)和重要性,動態(tài)調整其OOM值,以優(yōu)化系統(tǒng)內存管理。applyOomAdjLocked方法的核心功能和設計目的:
- 其核心功能是將之前通過computeOomAdjLocked方法計算得出的OOM值應用到各個進程上,以此來調整進程的內存優(yōu)先級。
- 設計目的在于確保在系統(tǒng)內存緊張時,能夠根據進程的重要性和當前狀態(tài),合理地決定哪些進程應該被優(yōu)先保留,哪些可以被犧牲以釋放內存資源。
通過這種方式,系統(tǒng)能夠在保證用戶體驗的同時,有效管理內存資源,避免因內存不足導致的系統(tǒng)不穩(wěn)定或崩潰。
3.2.2 updateOomAdjLocked后半段代碼解讀
updateOomAdjLocked后半段代碼實現(xiàn)如下所示:
final void updateOomAdjLocked() {//...// 更新服務進程數量mNumServiceProcs = mNewNumServiceProcs;// 計算緩存和空進程的總數final int numCachedAndEmpty = numCached + numEmpty;// 根據緩存和空進程的數量確定內存因子,用于調整進程的內存使用int memFactor;if (numCached <= ProcessList.TRIM_CACHED_APPS&& numEmpty <= ProcessList.TRIM_EMPTY_APPS) {if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {memFactor = ProcessStats.ADJ_MEM_FACTOR_CRITICAL;} else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {memFactor = ProcessStats.ADJ_MEM_FACTOR_LOW;} else {memFactor = ProcessStats.ADJ_MEM_FACTOR_MODERATE;}} else {memFactor = ProcessStats.ADJ_MEM_FACTOR_NORMAL;}// 如果新的內存因子大于上次的內存因子,且不允許降低內存級別或進程數量沒有變化,則保持上次的內存因子if (memFactor > mLastMemoryLevel) {if (!mAllowLowerMemLevel || mLruProcesses.size() >= mLastNumProcesses) {memFactor = mLastMemoryLevel;}}// 更新上次的內存因子和進程數量mLastMemoryLevel = memFactor;mLastNumProcesses = mLruProcesses.size();// 根據內存因子更新進程的狀態(tài)boolean allChanged = mProcessStats.setMemFactorLocked(memFactor, !isSleeping(), now);final int trackerMemFactor = mProcessStats.getMemFactorLocked();// 如果內存因子不是正常級別,則根據內存狀況對進程進行內存修剪if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {// 記錄低內存開始時間if (mLowRamStartTime == 0) {mLowRamStartTime = now;}// 根據內存因子確定修剪級別int fgTrimLevel;switch (memFactor) {case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;break;case ProcessStats.ADJ_MEM_FACTOR_LOW:fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;break;default:fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;break;}// 計算修剪步長int factor = numTrimming / 3;int minFactor = 2;if (mHomeProcess != null) minFactor++;if (mPreviousProcess != null) minFactor++;if (factor < minFactor) factor = minFactor;// 遍歷所有進程,根據修剪級別進行內存修剪int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;for (int i = N - 1; i >= 0; i--) {ProcessRecord app = mLruProcesses.get(i);if (allChanged || app.procStateChanged) {setProcessTrackerStateLocked(app, trackerMemFactor, now);app.procStateChanged = false;}// 對于HOME和PREVIOUS進程,以及需要修剪的進程,進行內存修剪if (app.curProcState >= ActivityManager.PROCESS_STATE_HOME&& !app.killedByAm) {if (app.trimMemoryLevel < curLevel && app.thread != null) {try {app.thread.scheduleTrimMemory(curLevel);} catch (RemoteException e) {}}app.trimMemoryLevel = curLevel;// 更新修剪級別step++;if (step >= factor) {step = 0;switch (curLevel) {case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:curLevel = ComponentCallbacks2.TRIM_MEMORY_MODERATE;break;case ComponentCallbacks2.TRIM_MEMORY_MODERATE:curLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;break;}}} else if (app.curProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {// 對于重量級進程,進行背景內存修剪if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND&& app.thread != null) {try {app.thread.scheduleTrimMemory(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);} catch (RemoteException e) {}}app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;} else {// 對于其他進程,根據需要進行內存修剪if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND|| app.systemNoUi) && app.pendingUiClean) {final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;if (app.trimMemoryLevel < level && app.thread != null) {try {app.thread.scheduleTrimMemory(level);} catch (RemoteException e) {}}app.pendingUiClean = false;}if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {try {app.thread.scheduleTrimMemory(fgTrimLevel);} catch (RemoteException e) {}}app.trimMemoryLevel = fgTrimLevel;}}} else {// 如果內存因子是正常級別,則重置低內存開始時間if (mLowRamStartTime != 0) {mLowRamTimeSinceLastIdle += now - mLowRamStartTime;mLowRamStartTime = 0;}for (int i = N - 1; i >= 0; i--) {ProcessRecord app = mLruProcesses.get(i);if (allChanged || app.procStateChanged) {setProcessTrackerStateLocked(app, trackerMemFactor, now);app.procStateChanged = false;}// 對于需要清理UI的進程,進行UI隱藏內存修剪if ((app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND|| app.systemNoUi) && app.pendingUiClean) {if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN&& app.thread != null) {try {app.thread.scheduleTrimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);} catch (RemoteException e) {}}app.pendingUiClean = false;}app.trimMemoryLevel = 0;}}// 如果設置了總是結束活動的選項,則安排銷毀所有活動if (mAlwaysFinishActivities) {mStackSupervisor.scheduleDestroyAllActivities(null, "always-finish");}// 如果所有進程的狀態(tài)都發(fā)生了變化,則請求所有進程的PSS(Proportional Set Size)數據if (allChanged) {requestPssAllProcsLocked(now, false, mProcessStats.isMemFactorLowered());}// 如果進程統(tǒng)計數據應該被寫入,則異步寫入if (mProcessStats.shouldWriteNowLocked(now)) {mHandler.post(new Runnable() {@Override public void run() {synchronized (ActivityManagerService.this) {mProcessStats.writeStateAsyncLocked();}}});}}
后半部分則專注于根據當前的內存使用情況來調整進程的內存使用級別,即內存因子(memFactor)。它通過計算得出當前的內存因子,并根據該因子對進程進行內存修剪,以釋放內存資源。這一部分還涉及到更新進程的內存修剪級別,并在必要時觸發(fā)進程的內存修剪操作,以響應系統(tǒng)的內存壓力。
在updateOomAdjLocked
方法中,根據前半段和后半段的代碼,針對oom_adj關鍵變量的調整主要集中在以下幾個方面,解讀如下:
- OOM調整值(
curAdj
):每個ProcessRecord
對象中的curAdj
字段被調整,這個字段代表了進程的當前OOM調整值,它直接影響到進程在內存不足時被殺死的優(yōu)先級。 - 進程狀態(tài)(
curProcState
):ProcessRecord
中的curProcState
字段被更新,反映了進程的當前狀態(tài),如前臺、后臺、服務等,這有助于確定進程的OOM調整值。 - 內存因子(
memFactor
):memFactor
變量根據系統(tǒng)的內存狀況和進程的數量被計算出來,用于決定整體的內存調整策略。 - 服務進程計數(
mNewNumServiceProcs
和mNumServiceProcs
):mNewNumServiceProcs
用于臨時計數服務進程的數量,而mNumServiceProcs
是最終的服務進程數量,這些計數用于內存調整決策。 - 非緩存進程和緩存隱藏進程計數(
mNumNonCachedProcs
和mNumCachedHiddenProcs
):這些變量用于計數非緩存進程和緩存隱藏進程的數量,它們在計算OOM調整值時起到重要作用。 - 進程跟蹤器狀態(tài)(
setProcessTrackerStateLocked
):該方法被調用來更新進程的內存修剪級別,這影響了進程如何響應系統(tǒng)的內存壓力。 - 內存修剪級別(
trimMemoryLevel
):trimMemoryLevel
字段在ProcessRecord
中被設置,指示進程應該采取的內存修剪行動。 - 低內存開始時間(
mLowRamStartTime
):記錄系統(tǒng)進入低內存狀態(tài)的時間,用于跟蹤和管理低內存期間的內存調整策略。
這些關鍵變量的調整確保了Android系統(tǒng)能夠根據當前的內存狀況和進程的活動狀態(tài),動態(tài)地管理內存資源,優(yōu)化用戶體驗,并在內存不足時做出合理的進程殺死決策。通過這種方式,系統(tǒng)能夠在保證前臺和關鍵進程的穩(wěn)定性的同時,合理回收后臺進程的內存資源。
updateOomAdjLocked方法整體上是Android系統(tǒng)中一個關鍵的內存管理機制,它確保了在內存資源有限的情況下,系統(tǒng)能夠根據進程的重要性和活動狀態(tài)動態(tài)調整其OOM調整值和內存使用級別。通過這種方法,系統(tǒng)能夠在內存不足時優(yōu)先保護前臺和關鍵進程,同時合理地回收后臺進程的內存資源,從而優(yōu)化整體的系統(tǒng)性能和用戶體驗。這個方法體現(xiàn)了Android系統(tǒng)在面對不同內存壓力時的響應策略,包括進程的OOM調整、內存修剪和進程狀態(tài)的更新,這些都是為了在保證系統(tǒng)穩(wěn)定性的同時,盡可能地提高內存使用效率。