AndroidQ 的进程清理机制Process_Reclaim

一,Kernel 空间

1. @kernel-4.9\mm\Kconfig

config PROCESS_RECLAIM

bool "Enable process reclaim"

depends on PROC_FS

default n

help

It allows to reclaim pages of the process by /proc/pid/reclaim.

(echo file > /proc/PID/reclaim) reclaims file-backed pages only.

(echo anon > /proc/PID/reclaim) reclaims anonymous pages only.

(echo all > /proc/PID/reclaim) reclaims all pages.

Any other value is ignored.

 

2. @Vmscan.c (mm) 119815 6/4/2020

#ifdef CONFIG_PROCESS_RECLAIM

unsigned long reclaim_pages(struct list_head *page_list)

{

unsigned long dummy1, dummy2, dummy3, dummy4, dummy5;

unsigned long nr_reclaimed;

struct page *page;

unsigned long nr_isolated[2] = {0, };

struct pglist_data *pgdat = NULL;

struct scan_control sc = {

.gfp_mask = GFP_KERNEL,

.priority = DEF_PRIORITY,

.may_writepage = 1, //可以回写到文件

.may_unmap = 1, //可以解除虚拟内存映射

.may_swap = 1, //可以交换到zram

};

if (list_empty(page_list))

return 0;

 

list_for_each_entry(page, page_list, lru) {

ClearPageActive(page);//首先清除page的active状态

if (pgdat == NULL)

pgdat = page_pgdat(page);

/* XXX: It could be multiple node in other config */

WARN_ON_ONCE(pgdat != page_pgdat(page));

if (!page_is_file_cache(page))

nr_isolated[0]++;

else

nr_isolated[1]++;

}

 

mod_node_page_state(pgdat, NR_ISOLATED_ANON, nr_isolated[0]);

mod_node_page_state(pgdat, NR_ISOLATED_FILE, nr_isolated[1]);

//根据sc设置的清理参数,开始逐个清理page_list中的页

nr_reclaimed = shrink_page_list(page_list, pgdat, &sc,

TTU_UNMAP|TTU_IGNORE_ACCESS,

&dummy1, &dummy2, &dummy3, &dummy4, &dummy5, true);

 

while (!list_empty(page_list)) {//如果还有没有被清理完的page,则又放回到LRU缓冲列表中

page = lru_to_page(page_list);

list_del(&page->lru);

putback_lru_page(page);

}

 

mod_node_page_state(pgdat, NR_ISOLATED_ANON, -nr_isolated[0]);

mod_node_page_state(pgdat, NR_ISOLATED_FILE, -nr_isolated[1]);

 

return nr_reclaimed;

}

#endif

 

3. @Task_mmu.c (fs\proc) 50858 5/20/2020

#ifdef CONFIG_PROCESS_RECLAIM

enum reclaim_type {

RECLAIM_FILE,

RECLAIM_ANON,

RECLAIM_ALL,

};

//清理file cache页面, 没有回写到磁盘,而只是简单的把该页移动到 inactive file cache的LRU列表中

//为了防止回写文件造成的block? 而标准的kernel patch是需要回写到磁盘的!

static int deactivate_pte_range(pmd_t *pmd, unsigned long addr,

unsigned long end, struct mm_walk *walk)

{

pte_t *orig_pte, *pte, ptent;

spinlock_t *ptl;

struct page *page;

struct vm_area_struct *vma = walk->vma;

 

orig_pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);

for (pte = orig_pte; addr < end; pte++, addr += PAGE_SIZE) {

ptent = *pte;

 

if (pte_none(ptent))

continue;

 

if (!pte_present(ptent))

continue;

//通过虚拟映射表,获取实际的物理页

page = vm_normal_page(vma, addr, ptent);

if (!page)

continue;

/*

* XXX: we don't handle compound page at this moment but

* it should revisit for THP page before upstream.

*/

if (PageCompound(page)) {

unsigned int order = compound_order(page);

unsigned int nr_pages = (1 << order) - 1;

 

addr += (nr_pages * PAGE_SIZE);

pte += nr_pages;

continue;

}

 

if (page_mapcount(page) > 1)

continue;

 

ptep_test_and_clear_young(vma, addr, pte);

test_and_clear_page_young(page);

if (PageReferenced(page))

ClearPageReferenced(page);

if (PageActive(page))

deactivate_page(page); //把该页移动到inactive list,内存不够时会被直接回收

}

 

pte_unmap_unlock(orig_pte, ptl);

cond_resched();

return 0;

}

 

//清理进程中的匿名页

static int reclaim_pte_range(pmd_t *pmd, unsigned long addr,

unsigned long end, struct mm_walk *walk)

{

pte_t *orig_pte, *pte, ptent;

spinlock_t *ptl;

LIST_HEAD(page_list);

struct page *page;

int isolated = 0;

struct vm_area_struct *vma = walk->vma;

 

orig_pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);

for (pte = orig_pte; addr < end; pte++, addr += PAGE_SIZE) {

ptent = *pte;

if (!pte_present(ptent))

continue;

//通过虚拟映射表,获取实际的物理页

page = vm_normal_page(vma, addr, ptent);

if (!page)

continue;

/*

* XXX: we don't handle compound page at this moment but

* it should revisit for THP page before upstream.

*/

if (PageCompound(page)) {

unsigned int order = compound_order(page);

unsigned int nr_pages = (1 << order) - 1;

 

addr += (nr_pages * PAGE_SIZE);

pte += nr_pages;

continue;

}

if (!PageLRU(page))//判断该页是否在LRU缓存链表中,如果不是则不能回收

continue;

if (page_mapcount(page) > 1)//判断该页被映射的次数,如果多次被map也不能被回收

continue;

if (isolate_lru_page(page))

continue;

isolated++;

list_add(&page->lru, &page_list);//添加page到可以清理的page_list中

//一次最多清理32个页面,为啥?防止阻塞

if (isolated >= SWAP_CLUSTER_MAX) { //SWAP_CLUSTER_MAX = 32

pte_unmap_unlock(orig_pte, ptl);

reclaim_pages(&page_list);

isolated = 0;

pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);

orig_pte = pte;

}

}

 

pte_unmap_unlock(orig_pte, ptl);

reclaim_pages(&page_list);//清理该进程中可以清理的匿名页

 

cond_resched();

return 0;

}

 

static ssize_t reclaim_write(struct file *file, const char __user *buf,

size_t count, loff_t *ppos)

{

struct task_struct *task;

char buffer[PROC_NUMBUF];

struct mm_struct *mm;

struct vm_area_struct *vma;

enum reclaim_type type;

char *type_buf;

 

if (!capable(CAP_SYS_NICE))

return -EPERM;

 

memset(buffer, 0, sizeof(buffer));

if (count > sizeof(buffer) - 1)

count = sizeof(buffer) - 1;

 

if (copy_from_user(buffer, buf, count))

return -EFAULT;

 

type_buf = strstrip(buffer);

if (!strcmp(type_buf, "file"))

type = RECLAIM_FILE;

else if (!strcmp(type_buf, "anon"))

type = RECLAIM_ANON;

else if (!strcmp(type_buf, "all"))

type = RECLAIM_ALL;

else

return -EINVAL;

 

task = get_proc_task(file->f_path.dentry->d_inode);//根据PID获取进程task结构

if (!task)

return -ESRCH;

 

mm = get_task_mm(task);//获取当前进程的内存结构

if (mm) {

struct mm_walk reclaim_walk = {

.pmd_entry = reclaim_pte_range,

.mm = mm,

};

 

down_read(&mm->mmap_sem);

//遍历当前进程所占用的虚拟地址

for (vma = mm->mmap; vma; vma = vma->vm_next) {

if (is_vm_hugetlb_page(vma))//没有打开CONFIG_HUGETLB_PAGE

continue;

if (vma->vm_flags & VM_LOCKED)

continue;

if (type == RECLAIM_ANON && !vma_is_anonymous(vma))

continue; //只reclaim匿名页,不是则返回

if (type == RECLAIM_FILE && vma_is_anonymous(vma))

continue; //只reclaim 文件缓存页,不是则返回

if (vma_is_anonymous(vma)) //匿名页虚拟映射

reclaim_walk.pmd_entry = reclaim_pte_range;

else //文件缓存页虚拟映射

reclaim_walk.pmd_entry = deactivate_pte_range; //MTK单独添加

//扫描虚拟内存空间, 根据设置的回调函数逐个处理

walk_page_range(vma->vm_start, vma->vm_end,

&reclaim_walk);

}

flush_tlb_mm(mm);

up_read(&mm->mmap_sem);

mmput(mm);

}

put_task_struct(task);

 

return count;

}

 

const struct file_operations proc_reclaim_operations = {

.write = reclaim_write,

.llseek = noop_llseek,

};

#endif

 

4. @Base.c (fs\proc) 86823 5/20/2020

static const struct pid_entry tgid_base_stuff[] = {

REG("mountinfo", S_IRUGO, proc_mountinfo_operations),

REG("mountstats", S_IRUSR, proc_mountstats_operations),

#ifdef CONFIG_PROCESS_RECLAIM

REG("reclaim", 0222, proc_reclaim_operations),

#endif

}

 

二, 用户Android空间

1. @OomAdjuster.java (frameworks\base\services\core\java\com\android\server\am)

/**

* Service for compacting background apps.

*/

AppCompactor mAppCompact;

OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {

mConstants = mService.mConstants;

mAppCompact = new AppCompactor(mService);

}

 

void initSettings() {

mAppCompact.init();

}

 

private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,

int changes = 0;

// don't compact during bootup,

if (mAppCompact.useCompaction() && mService.mBooted) {

// Cached and prev/home compaction

//按进程adj的值清理其内存(file cache or anon pages)!!!

//同时还收每个进程清理的间隔限制,不能清理太频繁了(导致没啥可清理的)

if (app.curAdj != app.setAdj) {

// Perform a minor compaction when a perceptible app becomes the prev/home app

// Perform a major compaction when any app enters cached

// reminder: here, setAdj is previous state, curAdj is upcoming state

if (app.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ &&

(app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||

app.curAdj == ProcessList.HOME_APP_ADJ)) {

//可感知app变成home和前一个app则清理file cache

mAppCompact.compactAppSome(app);

} else if ((app.setAdj < ProcessList.CACHED_APP_MIN_ADJ

|| app.setAdj > ProcessList.CACHED_APP_MAX_ADJ)

&& app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ

&& app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) {

//除上条件后的app变为缓存app, 则清理file cache和压缩swap匿名页

mAppCompact.compactAppFull(app);

}

} else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE

&& app.setAdj < ProcessList.FOREGROUND_APP_ADJ

// Because these can fire independent of oom_adj/procstate changes, we need

// to throttle the actual dispatch of these requests in addition to the

// processing of the requests. As a result, there is throttling both here

// and in AppCompactor.

&& mAppCompact.shouldCompactPersistent(app, now)) {

//手机处于非全唤醒状态,则清理persistent app的file cache和压缩swap匿名页

mAppCompact.compactAppPersistent(app);

} else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE

&& app.getCurProcState()

== ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE

&& mAppCompact.shouldCompactBFGS(app, now)) {

//手机处于非全唤醒状态,被系统调用的前台服务,则清理app的file cache和匿名页

mAppCompact.compactAppBfgs(app);

}

}

}

 

2. @AppCompactor.java (frameworks\base\services\core\java\com\android\server\am)

private void updateUseCompaction() {

//从哪读取的这个配置参数?????

//DeviceConfig.getBoolean ->Settings.Config.getString

->读取/data/system/users/0/settings_config.xml

mUseCompaction = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,

KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);

if (mUseCompaction && !mCompactionThread.isAlive()) {

mCompactionThread.start();

mCompactionHandler = new MemCompactionHandler();

}

}

 

@GuardedBy("mAm") //表示受与mAm引用相关联的锁 保护

void compactAppSome(ProcessRecord app) {

app.reqCompactAction = COMPACT_PROCESS_SOME;//设置清理类型

mPendingCompactionProcesses.add(app);//添加到列表中,消息处理函数中再取出

mCompactionHandler.sendMessage(//发送消息异步处理

mCompactionHandler.obtainMessage(

COMPACT_PROCESS_MSG, app.setAdj, app.setProcState));

}

void compactAppFull(ProcessRecord app)

void compactAppPersistent(ProcessRecord app)

void compactAppBfgs(ProcessRecord app)

以上针对APP内存压缩处理的函数都是发消息COMPACT_PROCESS_MSG 异步处理

 

@GuardedBy("mAm")

void compactAllSystem() { //系统启动完成和每天半夜会调用!!!清理系统整个内存

if (mUseCompaction) {

mCompactionHandler.sendMessage(mCompactionHandler.obtainMessage(

COMPACT_SYSTEM_MSG));

}

}

 

private native void compactSystem();

 

private final class MemCompactionHandler extends Handler {

private MemCompactionHandler() {

super(mCompactionThread.getLooper());

}

 

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case COMPACT_PROCESS_MSG: {

synchronized (mAm) {

proc = mPendingCompactionProcesses.remove(0);

pendingAction = proc.reqCompactAction;

//通过设置的compact条件,逐个判断是否需要清理该进程,

//1. 如果进程已经为PERCEPTIBLE_APP_ADJ,可感知App,则不做清理

//2. App不能清理太频繁(可以参考调试条目中的参数解释)

//compact_throttle_1=5000 如果上次是轻度清理,这次轻度compact清理两者时间间隔5秒

//compact_throttle_2=10000 如果上次是重度清理,这次轻度compact清理两者时间间隔10秒

//compact_throttle_3=500 如果上次是轻度清理,这次重度compact清理两者时间间隔0.5秒

//compact_throttle_4=10000 如果上次是重度清理,这次重度compact清理两者时间间隔10秒

//compact_throttle_5=600000 两次被系统绑定调用的前台服务重度清理间隔10分钟

//compact_throttle_6=600000 两次persisit app的重度清理间隔10分钟

//3. 确定清理action,

//compact_action_1=file 轻度compact清理,只清理file cache

//compact_action_2=all 重度compact清理,清理file cahce和匿名页zram压缩

//4. 如果清理匿名页

//compact_full_rss_throttle_kb=12000 进程占用RSS(实际使用内存包含所有共享内存)的最低清理门限为12M

//compact_full_delta_rss_throttle_kb=8000 进程被清理过,再次清理时比较上次清理完后占用的RSS和当前占用的RSS相比较,如果没有增加超出该门限8M,则不再清理

//5.以上条件都不满足,则开始清理app内存

try {

long zramFreeKbBefore = Debug.getZramFreeKb();

FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim");

fos.write(action.getBytes()); //写文件节点,触发进程内存清理

fos.close();

 

break;

}

case COMPACT_SYSTEM_MSG: {

compactSystem();

break;

}

}

 

3. @com_android_server_am_AppCompactor.cpp (frameworks\base\services\core\jni)

// This performs per-process reclaim on all processes belonging to non-app UIDs.

// For the most part, these are non-zygote processes like Treble HALs, but it

// also includes zygote-derived processes that run in system UIDs, like bluetooth

// or potentially some mainline modules. The only process that should definitely

// not be compacted is system_server, since compacting system_server around the

// time of BOOT_COMPLETE could result in perceptible issues.

static void com_android_server_am_AppCompactor_compactSystem(JNIEnv *, jobject) {

std::unique_ptr<DIR, decltype(&closedir)> proc(opendir("/proc"), closedir);

struct dirent* current;

//遍历proc/节点,获取进程信息,这将是一个耗时的过程

while ((current = readdir(proc.get()))) {

if (current->d_type != DT_DIR) {

continue;

}

// don't compact system_server, rely on persistent compaction during screen off

// in order to avoid mmap_sem-related stalls

if (atoi(current->d_name) == getpid()) { //不清理自身system_server的内存

continue;

}

std::string status_name = StringPrintf("/proc/%s/status", current->d_name);

struct stat status_info;

if (stat(status_name.c_str(), &status_info) != 0) {

// must be some other directory that isn't a pid

continue;

}

// android.os.Process.FIRST_APPLICATION_UID

if (status_info.st_uid >= 10000) {//只清理非用户进程,比如系统进程和Native进程

continue;

}

 

std::string reclaim_path = StringPrintf("/proc/%s/reclaim", current->d_name);

WriteStringToFile(std::string("all"), reclaim_path);

}

}

 

4. ActivityManagerService.java (frameworks\base\services\core\java\com\android\server\am)

final void finishBooting() {

mUserController.sendBootCompleted(

new IIntentReceiver.Stub() {

@Override

public void performReceive(Intent intent, int resultCode,

String data, Bundle extras, boolean ordered,

boolean sticky, int sendingUser) {

synchronized (ActivityManagerService.this) {

//系统启动完成后开始清理系统进程

mOomAdjuster.mAppCompact.compactAllSystem();

requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);

}

}

});

}

 

@Override

public void performIdleMaintenance() {

synchronized (this) {

// Compact all non-zygote processes to freshen up the page cache.

mOomAdjuster.mAppCompact.compactAllSystem();

 

}

 

5. @StorageManagerService.java (frameworks\base\services\core\java\com\android\server)

private void handleSystemReady() {

// Start scheduling nominally-daily fstrim operations

MountServiceIdler.scheduleIdlePass(mContext);

}

 

6. @MountServiceIdler.java (frameworks\base\services\core\java\com\android\server)

public static void scheduleIdlePass(Context context) {

JobScheduler tm = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);

Calendar calendar = tomorrowMidnight();

final long timeToMidnight = calendar.getTimeInMillis() - System.currentTimeMillis();

//创建job, 触发条件是系统IDLE, 充电,时间为第二天半夜3点, 只运行一次

JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService);

builder.setRequiresDeviceIdle(true);

builder.setRequiresCharging(true);

builder.setMinimumLatency(timeToMidnight);

tm.schedule(builder.build());

}

 

public boolean onStartJob(JobParameters params) {

// First have the activity manager do its idle maintenance. (Yes this job

// is really more than just mount, some day it should be renamed to be system

// idleer).

try {

ActivityManager.getService().performIdleMaintenance();

} catch (RemoteException e) {

}

 

StorageManagerService ms = StorageManagerService.sSelf;

if (ms != null) {

synchronized (mFinishCallback) {

mStarted = true;

}

ms.runIdleMaint(mFinishCallback);

}

}

 

private Runnable mFinishCallback = new Runnable() {

@Override

public void run() {

Slog.i(TAG, "Got mount service completion callback");

synchronized (mFinishCallback) {

if (mStarted) {

jobFinished(mJobParams, false);

mStarted = false;

}

}

// ... and try again tomorrow, 重新创建job

scheduleIdlePass(MountServiceIdler.this);

}

};

 

三, 调试

1. #dumpsys activity settings

AppCompactor settings

use_compaction=true 表示使用单个进程内存清理功能

compact_action_1=file 轻度compact清理,只清理file cache

compact_action_2=all 重度compact清理,清理file cahce和匿名页zram压缩

compact_throttle_1=5000 如果上次是轻度清理,这次轻度compact清理两者时间间隔5秒

compact_throttle_2=10000 如果上次是重度清理,这次轻度compact清理两者时间间隔10秒

compact_throttle_3=500 如果上次是轻度清理,这次重度compact清理两者时间间隔0.5秒

compact_throttle_4=10000 如果上次是重度清理,这次重度compact清理两者时间间隔10秒

compact_throttle_5=600000 两次被系统绑定调用的前台服务重度清理间隔10分钟

compact_throttle_6=600000 两次persisit app的重度清理间隔10分钟

compact_statsd_sample_rate=0.1 随机更新compact事件给statsd的采样间隔

compact_full_rss_throttle_kb=12000 进程占用RSS(实际使用内存包含所有共享内存)的最低清理门限为12M

compact_full_delta_rss_throttle_kb=8000 进程被清理过,再次清理时比较上次清理完后占用的RSS和当前占用的RSS相比较,如果没有增加超出该门限8M,则不再清理

compact_proc_state_throttle=[12] 当进程状态为12(PROCESS_STATE_RECEIVER)时,则不做清理。清理排除的进程状态

31 some, 104 full, 79 persistent, 35 BFGS compactions. //记录已经被内存清理处理过的次数, some表示轻度清理,full表示重度清理

Tracking last compaction stats for 40 processes.

MTBF 跑完后:

7695 some, 45640 full, 927 persistent, 379 BFGS compactions.

Tracking last compaction stats for 96 processes.

 

2. #logcat -b events -s am_compact

06-10 14:13:55.085 1059 1159 I am_compact: [32436,com.google.android.gms,all,121800,101540,18792,14004,-7768,0,-7768,7768,159,2,448136726,1001,20,471428,-7768]

数据具体说明:

com.google.android.gms表示被清理的进程名称

all 表示清理操作的类型, file是只清理file cache, all是清理file cache和匿名页

121800,101540,18792,14004 表示清理前进程的4个RSS值

-7768,0,-7768,7768 表示清理后进程这4个RSS的差值,负数表示减少,正数表示增加

159 清理操作消耗的时间,单位为ms

2 表示清理进程类型 1:filecache清理;2: filecache&匿名页清理; 3: persistent进程清理; 4:前台服务清理

448136726 上一次进程清理时的系统时间

1001 清理前进程的adj

20 清理前的进程状态 PROCESS_STATE_CACHED_EMPTY=20 @ActivityManager.java

ActivityManager.java (frameworks\base\core\java\android\app) 166084 5/20/2020

471428 进程清理前free zram的大小

-7768 进程清理后free zram的变化值, 负数表示减少,正数表示增加

 

06-10 14:32:51.786 1059 1159 I am_compact: [30930,com.facebook.appmanager,all,75452,60612,14228,14524,-3464,0,-3464,3464,81,2,448172391,1001,20,467628,-3452]

06-10 15:07:24.910 1059 1159 I am_compact: [26856,android.process.acore,file,65492,47008,18164,5860,0,0,0,0,8,1,445391394,0,6,502496,0]

06-10 15:07:25.462 1059 1159 I am_compact: [29866,com.google.android.apps.photos,all,114724,99648,13964,30692,-1924,0,-1924,1924,50,2,439030180,1001,19,505044,-720]

06-10 15:07:25.990 1059 1159 I am_compact: [24686,com.google.process.gservices,file,62472,46840,15348,6092,0,0,0,0,9,0,0,100,6,516600,0]

06-10 15:07:26.771 1059 1159 I am_compact: [24822,com.google.android.partnersetup,all,57540,41448,15808,6160,-2268,0,-2268,2268,48,0,0,1001,20,516796,-1832]

 

3. 如何通过修改config配置

DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,

KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);

-->DeviceConfig.getBoolean("activity_manager", "use_compaction", true)

在/data/system/users/0/settings_config.xml中添加其定义

<settings version="-1">

<setting id="0" name="connectivity/captive_portal_use_https" value="0" package="android" defaultValue="0" defaultSysSet="true" tag="null" />

<setting id="1" name="activity_manager/use_compaction" value="0" package="android" defaultValue="0" defaultSysSet="true" />

</settings>

 

四,优化思路

1. 清理compactAllSystem是否频次可以更密点? 现在是开机结束和每天半夜充电且待机的情况下 才清理

 

2. 已经处于cache的进程是否有必要做内存清理? 因为很快会被kill掉

 

3. compactAllSystem只清理非用户进程,比如系统进程和Native进程,另外system_server不做清理

 

4. process reclaim是以进程为单位触发文件页,匿名页的内存优化策略。上层AMS根据adj的变化提供优化参数

  • 可感知app变成home和前一个app则清理file cache, 不清理匿名页,随时准备快速切换运行
  • 除上条件后的app变为缓存app, 则清理file cache和压缩swap匿名页。最大限度减少内存占用
  • 手机处于非全唤醒状态,则清理persistent app的file cache和压缩swap匿名页
  • 手机处于非全唤醒状态,被系统调用的前台服务,则清理app的file cache和匿名页

 

5. MTK对file cache页的清理做了优化,没有按照标准的kernel patch对匿名页和文件缓存页都做回收处理。而是简单的把active file cache LRU列表中的页移动到inactive file cache LRU.

 

6. 单个进程的内存清理,触发条件是否可以更激进些? 而不只是仅清理处于cache状态下的进程

 

7. 单个进程的内存清理,难道没有需要只清理匿名页的情况?

 

参考

https://www.jianshu.com/p/ae4ca096201a

https://lore.kernel.org/patchwork/patch/688100/ linux kernel patch for process reclaim

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值