Android O lowmemorykiller原理解析
技術標籤:Stability
文章目錄
1. LowmemoryKiller介紹
1.1 為什麼引入LowmemoryKiller?
程序的啟動分冷啟動和熱啟動,當用戶退出某一個程序的時候,並不會真正的將程序退出,而是將這個程序放到後臺,以便下次啟動的時候可以馬上啟動起來,這個過程名為熱啟動,這也是Android的設計理念之一。這個機制會帶來一個問題,每個程序都有自己獨立的記憶體地址空間,隨著應用開啟數量的增多,系統已使用的記憶體越來越大,就很有可能導致系統記憶體不足。為了解決這個問題,系統引入LowmemoryKiller(簡稱lmk)管理所有程序,根據一定策略來kill某個程序並釋放佔用的記憶體,保證系統的正常執行。
1.2 LMK基本原理?
所有應用程序都是從zygote孵化出來的,記錄在AMS中mLruProcesses列表中,由AMS進行統一管理,AMS中會根據程序的狀態更新程序對應的oom_adj值,這個值會通過檔案傳遞到kernel中去,kernel有個低記憶體回收機制,在記憶體達到一定閥值時會觸發清理oom_adj值高的程序騰出更多的記憶體空間,這就是Lowmemorykiller工作原理。
1.3 lmkd整體流程
-
AMS設定 /sys/module/lowmemorykiller/parameters/minfree和/sys/module/lowmemorykiller/parameters/adj節點標註當前系統的程序對應的adj值,已經對應的記憶體值minfree.在應用變化中設定/proc/pid/adj應用的當前adj值
-
lmkd讀取minfree,adj_score值知道記憶體的閾值,在讀取當前的剩餘記憶體,就知道殺死那些adj值
-
lmkd遍歷/proc/pid/adj值,知道各個程序的adj值,滿足條件的就殺死
參考link:
https://www.jianshu.com/p/221f4a246b45
1.4. 檢視程序adj值已經程序對應的型別
檢視程序1015的adj值為 -800。也可以通過adb shell dumpsys activity o/p
//第一種
msm8996_gvmq:/ # cat /proc/1015/oom_score_adj
-800
msm8996_gvmq:/ # cat /proc/1015/oom_adj
-14
//第二種
msm8996_gvmq:/ # dumpsys activity o | grep dms -A 3
PERS #29: pers F/ /PER trm: 5 1015:com.chinatsp.dmsservice.TDmsBootService/1000 (fixed)
oom: max=-800 curRaw=-800 setRaw=-800 cur=-800 set=-800
state: cur=PER set=PER lastPss=147MB lastSwapPss=0.00 lastCachedPss=0.00
cached=false empty=false hasAboveClient=false
minfree中數值的單位是記憶體中的頁面數量,一般情況下一個頁面是4KB。因此80640代表 80640*4k = 322560k,大概320M,對應殺死的adj值為906,也就是少於320M就殺死大於等於906的程序
//對應上面的一組數,每個陣列代表一個程序優先順序級別
msm8996_gvmq:/ # cat /sys/module/lowmemorykiller/parameters/adj
0,100,200,300,900,906
//裡面是以","分割的一組數,每個數字代表一個記憶體級別。
msm8996_gvmq:/ # cat /sys/module/lowmemorykiller/parameters/minfree
18432,23040,27648,32256,55296,80640
Ams設定的等級
@frameworks/base/services/core/java/com/android/server/am/ProcessList.java
//adj值 0,100,200,300,900,906
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
};
// These are the low-end OOM level limits. This is appropriate for an
// HVGA or smaller phone with less than 512MB. Values are in KB.
private final int[] mOomMinFreeLow = new int[] {
12288, 18432, 24576,
36864, 43008, 49152
};
//解析度記憶體高的專案: 對應minfree:18432,23040,27648,32256,55296,80640
private final int[] mOomMinFreeHigh = new int[] {
73728, 92160, 110592,
129024, 147456, 184320
};
各型別對應的adj值,
CACHED_APP_MAX_ADJ
@frameworks/base/services/core/java/com/android/server/am/ProcessList.java
static final int INVALID_ADJ = -10000;
// Adjustment used in certain places where we don't know it yet.
// (Generally this is something that is going to be cached, but we
// don't know the exact value in the cached range to assign yet.)
static final int UNKNOWN_ADJ = 1001;
// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
static final int CACHED_APP_MAX_ADJ = 906;
static final int CACHED_APP_MIN_ADJ = 900;
// The B list of SERVICE_ADJ -- these are the old and decrepit
// services that aren't as shiny and interesting as the ones in the A list.
static final int SERVICE_B_ADJ = 800;
// This is the process of the previous application that the user was in.
// This process is kept above other things, because it is very common to
// switch back to the previous app. This is important both for recent
// task switch (toggling between the two top recent apps) as well as normal
// UI flow such as clicking on a URI in the e-mail app to view in the browser,
// and then pressing back to return to e-mail.
static final int PREVIOUS_APP_ADJ = 700;
// This is a process holding the home application -- we want to try
// avoiding killing it, even if it would normally be in the background,
// because the user interacts with it so much.
static final int HOME_APP_ADJ = 600;
// This is a process holding an application service -- killing it will not
// have much of an impact as far as the user is concerned.
static final int SERVICE_ADJ = 500;
// This is a process with a heavy-weight application. It is in the
// background, but we want to try to avoid killing it. Value set in
// system/rootdir/init.rc on startup.
static final int HEAVY_WEIGHT_APP_ADJ = 400;
// This is a process currently hosting a backup operation. Killing it
// is not entirely fatal but is generally a bad idea.
static final int BACKUP_APP_ADJ = 300;
// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
// immediately visible. An example is background music playback.
static final int PERCEPTIBLE_APP_ADJ = 200;
// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear.
static final int VISIBLE_APP_ADJ = 100;
static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;
// This is the process running the current foreground app. We'd really
// rather not kill it!
static final int FOREGROUND_APP_ADJ = 0;
// This is a process that the system or a persistent process has bound to,
// and indicated it is important.
static final int PERSISTENT_SERVICE_ADJ = -700;
// This is a system persistent process, such as telephony. Definitely
// don't want to kill it, but doing so is not completely fatal.
static final int PERSISTENT_PROC_ADJ = -800;
// The system process runs at the default adjustment.
static final int SYSTEM_ADJ = -900;
// Special code for native processes that are not being managed by the system (so
// don't have an oom adj assigned by the system).
static final int NATIVE_ADJ = -1000;
2. AMS怎麼調整adj和記憶體值minFree
在高通的shell中又發現,他有通過讀取機身總記憶體來設定minfree等級
@device/qcom/common/rootdir/etc/init.qcom.post_boot.sh
if [ "$arch_type" == "aarch64" ] && [ $MemTotal -gt 2097152 ]; then
echo 10 > /sys/module/process_reclaim/parameters/pressure_min
echo 1024 > /sys/module/process_reclaim/parameters/per_swap_size
echo "18432,23040,27648,32256,55296,80640" > /sys/module/lowmemorykiller/parameters/minfree
echo 81250 > /sys/module/lowmemorykiller/parameters/vmpressure_file_min
elif [ "$arch_type" == "aarch64" ] && [ $MemTotal -gt 1048576 ]; then
echo 10 > /sys/module/process_reclaim/parameters/pressure_min
echo 1024 > /sys/module/process_reclaim/parameters/per_swap_size
echo "14746,18432,22118,25805,40000,55000" > /sys/module/lowmemorykiller/parameters/minfree
echo 81250 > /sys/module/lowmemorykiller/parameters/vmpressure_file_min
elif [ "$arch_type" == "aarch64" ]; then
echo 50 > /sys/module/process_reclaim/parameters/pressure_min
echo 512 > /sys/module/process_reclaim/parameters/per_swap_size
echo "14746,18432,22118,25805,40000,55000" > /sys/module/lowmemorykiller/parameters/minfree
echo 81250 > /sys/module/lowmemorykiller/parameters/vmpressure_file_min
else
echo 50 > /sys/module/process_reclaim/parameters/pressure_min
echo 512 > /sys/module/process_reclaim/parameters/per_swap_size
echo "15360,19200,23040,26880,34415,43737" > /sys/module/lowmemorykiller/parameters/minfree
echo 53059 > /sys/module/lowmemorykiller/parameters/vmpressure_file_min
fi
2.1 AMS設定minfree
Ams設定的等級
@frameworks/base/services/core/java/com/android/server/am/ProcessList.java
//adj值 0,100,200,300,900,906
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
};
// These are the low-end OOM level limits. This is appropriate for an
// HVGA or smaller phone with less than 512MB. Values are in KB.
private final int[] mOomMinFreeLow = new int[] {
12288, 18432, 24576,
36864, 43008, 49152
};
//解析度記憶體高的專案: 對應minfree:18432,23040,27648,32256,55296,80640
private final int[] mOomMinFreeHigh = new int[] {
73728, 92160, 110592,
129024, 147456, 184320
};
if (i == 4) high = (high3)/2;
else if (i == 5) high = (high7)/4;
因此計算公式:
184320 * 7 /4 = 322,560(記憶體大小) /4k = 80640
147456 *3 /2 = 221,184(記憶體大小)/4k = 55296
129024 / 4k = 32256
18432,23040,27648,32256,55296,80640 剛剛對應lmkd裡面的值
完成向lmkd寫minfree和adj節點資料
private void updateOomLevels(int displayWidth, int displayHeight, boolean write) {
// Scale buckets from avail memory: at 300MB we use the lowest values to
// 700MB or more for the top values.
float scaleMem = ((float)(mTotalMemMb-350))/(700-350);
// Scale buckets from screen size.
int minSize = 480*800; // 384000
int maxSize = 1280*800; // 1024000 230400 870400 .264
float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize);
if (false) {
Slog.i("XXXXXX", "scaleMem=" + scaleMem);
Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth
+ " dh=" + displayHeight);
}
float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp;
if (scale < 0) scale = 0;
else if (scale > 1) scale = 1;
int minfree_adj = Resources.getSystem().getInteger(
com.android.internal.R.integer.config_lowMemoryKillerMinFreeKbytesAdjust);
int minfree_abs = Resources.getSystem().getInteger(
com.android.internal.R.integer.config_lowMemoryKillerMinFreeKbytesAbsolute);
if (false) {
Slog.i("XXXXXX", "minfree_adj=" + minfree_adj + " minfree_abs=" + minfree_abs);
}
final boolean is64bit = Build.SUPPORTED_64_BIT_ABIS.length > 0;
//第4和5會擴大3/2 和7/4倍值
for (int i=0; i<mOomAdj.length; i++) {
int low = mOomMinFreeLow[i];
int high = mOomMinFreeHigh[i];
if (is64bit) {
// Increase the high min-free levels for cached processes for 64-bit
if (i == 4) high = (high*3)/2;
else if (i == 5) high = (high*7)/4;
}
mOomMinFree[i] = (int)(low + ((high-low)*scale));
}
if (minfree_abs >= 0) {
for (int i=0; i<mOomAdj.length; i++) {
mOomMinFree[i] = (int)((float)minfree_abs * mOomMinFree[i]
/ mOomMinFree[mOomAdj.length - 1]);
}
}
if (minfree_adj != 0) {
for (int i=0; i<mOomAdj.length; i++) {
mOomMinFree[i] += (int)((float)minfree_adj * mOomMinFree[i]
/ mOomMinFree[mOomAdj.length - 1]);
if (mOomMinFree[i] < 0) {
mOomMinFree[i] = 0;
}
}
}
// The maximum size we will restore a process from cached to background, when under
// memory duress, is 1/3 the size we have reserved for kernel caches and other overhead
// before killing background processes.
mCachedRestoreLevel = (getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024) / 3;
// Ask the kernel to try to keep enough memory free to allocate 3 full
// screen 32bpp buffers without entering direct reclaim.
int reserve = displayWidth * displayHeight * 4 * 3 / 1024;
int reserve_adj = Resources.getSystem().getInteger(com.android.internal.R.integer.config_extraFreeKbytesAdjust);
int reserve_abs = Resources.getSystem().getInteger(com.android.internal.R.integer.config_extraFreeKbytesAbsolute);
if (reserve_abs >= 0) {
reserve = reserve_abs;
}
if (reserve_adj != 0) {
reserve += reserve_adj;
if (reserve < 0) {
reserve = 0;
}
}
//put LMK_TARGET,lmkd會解析這個
//put mOomMinFree:minfree
//put mOomAdj對應的adj值
if (write) {
ByteBuffer buf = ByteBuffer.allocate(4 * (2*mOomAdj.length + 1));
buf.putInt(LMK_TARGET);
for (int i=0; i<mOomAdj.length; i++) {
buf.putInt((mOomMinFree[i]*1024)/PAGE_SIZE);
buf.putInt(mOomAdj[i]);
}
writeLmkd(buf);
SystemProperties.set("sys.sysctl.extra_free_kbytes", Integer.toString(reserve));
}
// GB: 2048,3072,4096,6144,7168,8192
// HC: 8192,10240,12288,14336,16384,20480
}
2.2 什麼時候ams會設定lmkd的閾值
applyDisplaySize會呼叫updateOomLevels修改lmkd閾值
void applyDisplaySize(WindowManagerService wm) {
if (!mHaveDisplaySize) {
Point p = new Point();
// TODO(multi-display): Compute based on sum of all connected displays' resolutions.
wm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, p);
if (p.x != 0 && p.y != 0) {
updateOomLevels(p.x, p.y, true);
mHaveDisplaySize = true;
}
}
}
3. AMS設定當前程序adj值(/proc/pid/adj)
設定pid的adj值
/**
* Set the out-of-memory badness adjustment for a process.
*
* @param pid The process identifier to set.
* @param uid The uid of the app
* @param amt Adjustment value -- lmkd allows -16 to +15.
*
* {@hide}
*/
public static final void setOomAdj(int pid, int uid, int amt) {
if (amt == UNKNOWN_ADJ)
return;
long start = SystemClock.elapsedRealtime();
ByteBuffer buf = ByteBuffer.allocate(4 * 4);
buf.putInt(LMK_PROCPRIO); //LMK_PROCPRIO
buf.putInt(pid);
buf.putInt(uid);
buf.putInt(amt);
writeLmkd(buf);
long now = SystemClock.elapsedRealtime();
if ((now-start) > 250) {
Slog.w("ActivityManager", "SLOW OOM ADJ: " + (now-start) + "ms for pid " + pid
+ " = " + amt);
}
}
applyOomAdjLocked會判斷如果adj變化會重新設定setOomAdj
private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
long nowElapsed) {
boolean success = true;
if (app.curRawAdj != app.setRawAdj) {
String seempStr = "app_uid=" + app.uid
+ ",app_pid=" + app.pid + ",oom_adj=" + app.curAdj
+ ",setAdj=" + app.setAdj + ",hasShownUi=" + (app.hasShownUi ? 1 : 0)
+ ",cached=" + (app.cached ? 1 : 0)
+ ",fA=" + (app.foregroundActivities ? 1 : 0)
+ ",fS=" + (app.foregroundServices ? 1 : 0)
+ ",systemNoUi=" + (app.systemNoUi ? 1 : 0)
+ ",curSchedGroup=" + app.curSchedGroup
+ ",curProcState=" + app.curProcState + ",setProcState=" + app.setProcState
+ ",killed=" + (app.killed ? 1 : 0) + ",killedByAm=" + (app.killedByAm ? 1 : 0)
+ ",debugging=" + (app.debugging ? 1 : 0);
android.util.SeempLog.record_str(385, seempStr);
app.setRawAdj = app.curRawAdj;
}
int changes = 0;
if (app.curAdj != app.setAdj) {
ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.info.uid) {
String msg = "Set " + app.pid + " " + app.processName + " adj "
+ app.curAdj + ": " + app.adjType;
4. lmkd接收訊息原理
ams和lmkd程序通過socket連線併發送資料
private static boolean openLmkdSocket() {
try {
sLmkdSocket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET);
sLmkdSocket.connect(
new LocalSocketAddress("lmkd",
LocalSocketAddress.Namespace.RESERVED));
sLmkdOutputStream = sLmkdSocket.getOutputStream();
} catch (IOException ex) {
Slog.w(TAG, "lowmemorykiller daemon socket open failed");
sLmkdSocket = null;
return false;
}
return true;
}
private static void writeLmkd(ByteBuffer buf) {
//3次建立連線機會
for (int i = 0; i < 3; i++) {
if (sLmkdSocket == null) {
if (openLmkdSocket() == false) {
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
}
continue;
}
}
try {
sLmkdOutputStream.write(buf.array(), 0, buf.position());
return;
} catch (IOException ex) {
Slog.w(TAG, "Error writing to lowmemorykiller socket");
try {
sLmkdSocket.close();
} catch (IOException ex2) {
}
sLmkdSocket = null;
}
}
}
}
Lmkd編譯到/system/bin/lmkd
@system/core/lmkd/Android.bp
cc_binary {
name: "lmkd",
srcs: ["lmkd.c"],
shared_libs: [
"liblog",
"libprocessgroup",
"libcutils",
],
cflags: ["-Werror"],
init_rc: ["lmkd.rc"],
}
lmkd是init core的時候啟動,定義了socket lmkd
service lmkd /system/bin/lmkd
class core
group root readproc
critical
socket lmkd seqpacket 0660 system system
writepid /dev/cpuset/system-background/tasks
@system/core/lmkd/lmkd.c
enum lmk_cmd {
LMK_TARGET,
LMK_PROCPRIO,
LMK_PROCREMOVE,
};
//處理邏輯的地方
static void ctrl_command_handler(void) {
int ibuf[CTRL_PACKET_MAX / sizeof(int)];
int len;
int cmd = -1;
int nargs;
int targets;
len = ctrl_data_read((char *)ibuf, CTRL_PACKET_MAX);
if (len <= 0)
return;
nargs = len / sizeof(int) - 1;
if (nargs < 0)
goto wronglen;
cmd = ntohl(ibuf[0]);
switch(cmd) {
case LMK_TARGET: //設定INKERNEL_MINFREE_PATH值
targets = nargs / 2;
if (nargs & 0x1 || targets > (int)ARRAY_SIZE(lowmem_adj))
goto wronglen;
cmd_target(targets, &ibuf[1]);
break;
case LMK_PROCPRIO: //設定/proc/pid值
if (nargs != 3)
goto wronglen;
cmd_procprio(ntohl(ibuf[1]), ntohl(ibuf[2]), ntohl(ibuf[3]));
break;
case LMK_PROCREMOVE: //刪除值
if (nargs != 1)
goto wronglen;
cmd_procremove(ntohl(ibuf[1]));
break;
default:
ALOGE("Received unknown command code %d", cmd);
return;
}
return;
wronglen:
ALOGE("Wrong control socket read length cmd=%d len=%d", cmd, len);
}
寫ams傳過來的adj和minfree值,可見ams只是發起寫命令,lmkd才是寫的人
#define INKERNEL_MINFREE_PATH "/sys/module/lowmemorykiller/parameters/minfree"
#define INKERNEL_ADJ_PATH "/sys/module/lowmemorykiller/parameters/adj"
static void cmd_target(int ntargets, int *params) {
int i;
if (ntargets > (int)ARRAY_SIZE(lowmem_adj))
return;
for (i = 0; i < ntargets; i++) {
lowmem_minfree[i] = ntohl(*params++);
lowmem_adj[i] = ntohl(*params++);
}
lowmem_targets_size = ntargets;
if (has_inkernel_module) {
char minfreestr[128];
char killpriostr[128];
minfreestr[0] = '\0';
killpriostr[0] = '\0';
for (i = 0; i < lowmem_targets_size; i++) {
char val[40];
if (i) {
strlcat(minfreestr, ",", sizeof(minfreestr));
strlcat(killpriostr, ",", sizeof(killpriostr));
}
snprintf(val, sizeof(val), "%d", use_inkernel_interface ? lowmem_minfree[i] : 0);
strlcat(minfreestr, val, sizeof(minfreestr));
snprintf(val, sizeof(val), "%d", use_inkernel_interface ? lowmem_adj[i] : 0);
strlcat(killpriostr, val, sizeof(killpriostr));
}
writefilestring(INKERNEL_MINFREE_PATH, minfreestr); //write minfree
writefilestring(INKERNEL_ADJ_PATH, killpriostr); //write adj
}
}
LMK_PROCPRIO: cmd_procprio向/proc%d/oom_score_adj寫值
static void cmd_procprio(int pid, int uid, int oomadj) {
struct proc *procp;
char path[80];
char val[20];
int soft_limit_mult;
if (oomadj < OOM_SCORE_ADJ_MIN || oomadj > OOM_SCORE_ADJ_MAX) {
ALOGE("Invalid PROCPRIO oomadj argument %d", oomadj);
return;
}
snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", pid);
snprintf(val, sizeof(val), "%d", oomadj);
writefilestring(path, val);
...
}
5. lmkd kernel監測系統記憶體
static int __initlowmem_init(void)
{
register_shrinker(&lowmem_shrinker);
return 0;
}
static struct shrinker lowmem_shrinker = {
.shrink = lowmem_shrink,
.seeks = DEFAULT_SEEKS * 16
};
初始化lowmemorykiller,註冊cache shrinker,當空閒記憶體頁面不足時,核心程序kswpd會呼叫註冊的shrink回撥函式來回收頁面,在Android上,lowmemorykiller,是通過minifree與adj陣列來確認需要殺死的低優先順序程序,以此來釋放記憶體
例如,一組minifree與adj的閾值資料如下:
minifree:
15360,19200,23040,26880,34415,43737
adj:
0,58,117,176,529,1000
當記憶體低於43737x4KB時,會殺死adj大於1000的程序,當記憶體低於34415x4KB時,會殺死adj大於529的程序
static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask)
{
struct task_struct *p;
struct task_struct *selected = NULL;
int rem = 0;
int tasksize;
int i;
int min_adj = OOM_ADJUST_MAX + 1;
int selected_tasksize = 0;
int selected_oom_adj;
int array_size = ARRAY_SIZE(lowmem_adj);
// 獲取當前可用記憶體頁數
int other_free = global_page_state(NR_FREE_PAGES);
int other_file = global_page_state(NR_FILE_PAGES);
if (lowmem_adj_size < array_size)
array_size = lowmem_adj_size;
if (lowmem_minfree_size < array_size)
array_size = lowmem_minfree_size;
for (i = 0; i < array_size; i++) {
if (other_free < lowmem_minfree[i] &&
other_file < lowmem_minfree[i]) {
// 獲取需要被清除的adj閾值
min_adj = lowmem_adj[i];
break;
}
}
rem = global_page_state(NR_ACTIVE_ANON) +
global_page_state(NR_ACTIVE_FILE) +
global_page_state(NR_INACTIVE_ANON) +
global_page_state(NR_INACTIVE_FILE);
selected_oom_adj = min_adj;
read_lock(&tasklist_lock);
// 遍歷每個程序
for_each_process(p) {
struct mm_struct *mm;
int oom_adj;
task_lock(p);
mm = p->mm;
if (!mm) {
task_unlock(p);
continue;
}
oom_adj = mm->oom_adj;
if (oom_adj < min_adj) {
task_unlock(p);
continue;
}
tasksize = get_mm_rss(mm);
task_unlock(p);
if (tasksize <= 0)
continue;
if (selected) {
// 當adj小於閾值時,不殺程序
if (oom_adj < selected_oom_adj)
continue;
if (oom_adj == selected_oom_adj &&
tasksize <= selected_tasksize)
continue;
}
selected = p;
selected_tasksize = tasksize;
selected_oom_adj = oom_adj;
lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",
p->pid, p->comm, oom_adj, tasksize);
}
// 殺死所選的低優先順序程序
if (selected) {
lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
selected->pid, selected->comm,
selected_oom_adj, selected_tasksize);
force_sig(SIGKILL, selected);
rem -= selected_tasksize;
}
lowmem_print(4, "lowmem_shrink %d, %x, return %d\n",
nr_to_scan, gfp_mask, rem);
read_unlock(&tasklist_lock);
return rem;
}