Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中進程管理

Android中進程管理

編輯:關於Android編程

 

 

在android中,進程這個概念被淡化了,我們知道Android的每一個應用都是運行在一個獨立的DVM中,他們之間互不影響;應用退出之後,並沒有立馬殺死進程,進程依然停留在內存中,這麼做的目的是為了提高下次啟動時的速度。而在Android中管理進程的模塊是AMS,主要有LRU weight,OOM adj,Low Memory Killer共同來完成進程的管理。
1 LRU weight LRU(最近最少使用)weight 主要用來衡量LRU的權重,在android進程啟動之後,會以ProcessRecord類型的方式創建一個實例,保存到AMS的mLruProcesses變量中,mLurProcesses會以LRU的順序來存儲進程信息。當有一下情況時會更新mLruProcesses: 1.應用程序異常退出 2.調用AMS顯式殺死進程 3.啟動和調度四大組件 這裡以啟動和調度四大組件為例,它最終會調用AMS的updateLruProcessLock方法:
 final void updateLruProcessLocked(ProcessRecord app,
            boolean oomAdj, boolean updateActivityTime) {
        mLruSeq++;//lru序號加一
        updateLruProcessInternalLocked(app, oomAdj, updateActivityTime, 0);
    }
先將LRU序號加一,用於標記一次更新LRU的操作,然後調用updateLruProcessInternalLocked:
 private final void updateLruProcessInternalLocked(ProcessRecord app,
            boolean oomAdj, boolean updateActivityTime, int bestPos) {
        // put it on the LRU to keep track of when it should be exited.
        int lrui = mLruProcesses.indexOf(app);
        if (lrui >= 0) mLruProcesses.remove(lrui);
        
        int i = mLruProcesses.size()-1;
        int skipTop = 0;
        
        app.lruSeq = mLruSeq;
        
        // compute the new weight for this process.
        if (updateActivityTime) {
            app.lastActivityTime = SystemClock.uptimeMillis();
        }
        if (app.activities.size() > 0) {
            // If this process has activities, we more strongly want to keep
            // it around.
            app.lruWeight = app.lastActivityTime;
        } else if (app.pubProviders.size() > 0) {
            // If this process contains content providers, we want to keep
            // it a little more strongly.
            app.lruWeight = app.lastActivityTime - ProcessList.CONTENT_APP_IDLE_OFFSET;
            // Also don't let it kick out the first few real hidden processes.
            skipTop = ProcessList.MIN_HIDDEN_APPS;
        } else {
            // If this process doesn't have activities, we less strongly
            // want to keep it around, and generally want to avoid getting
            // in front of any very recently used activities.
            app.lruWeight = app.lastActivityTime - ProcessList.EMPTY_APP_IDLE_OFFSET;
            // Also don't let it kick out the first few real hidden processes.
            skipTop = ProcessList.MIN_HIDDEN_APPS;
        }
        
        while (i >= 0) {
            ProcessRecord p = mLruProcesses.get(i);
            // If this app shouldn't be in front of the first N background
            // apps, then skip over that many that are currently hidden.
            if (skipTop > 0 && p.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
                skipTop--;
            }
            if (p.lruWeight <= app.lruWeight || i < bestPos) {
                mLruProcesses.add(i+1, app);//添加到mLruProcesses合適的位置
                break;
            }
            i--;
        }
        if (i < 0) {
            mLruProcesses.add(0, app);
        }
         // 如果這個進程之後總有cotent provider或者Service,重新計算
        // If the app is currently using a content provider or service,
        // bump those processes as well.
        if (app.connections.size() > 0) {
            for (ConnectionRecord cr : app.connections) {
                if (cr.binding != null && cr.binding.service != null
                        && cr.binding.service.app != null
                        && cr.binding.service.app.lruSeq != mLruSeq) {
                    updateLruProcessInternalLocked(cr.binding.service.app, oomAdj,updateActivityTime, i+1);
                }
            }
        }
        if (app.conProviders.size() > 0) {
            for (ContentProviderRecord cpr : app.conProviders.keySet()) {
                if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) {
                    updateLruProcessInternalLocked(cpr.proc, oomAdj,
                            updateActivityTime, i+1);
                }
            }
        }        
      
        if (oomAdj) {
            updateOomAdjLocked();調用updateOomAdjLocked 更新oom adj值
        }
    }
這個函數主要作用 1.為該進程計算LRU序列號和LRU weight 2.根據計算出來的LRU weight,將該進程信息插入到mLRUProcesses合適的位置之中 3.如果該進程之中有content provider或者service,重新計算LRU weight 4.判斷是否需要調用updateOomAdjLocked函數來更新oom adj的值
到此為止updateLruProcessLocked結束,可以看出,這個函數只是調整進程的LRU weight和在mLruProcesses中的位置,並沒有直接參與進程的管理,真正參與進程管理的是updateOomAdjLocked函數,這個函數用來更新oom adj的值,這個值影響著進程的回收
2 OOM adj OOM adj 定義了一系列的OOM的調整級別,從-17到15。在Low Memory Killer機制中已經介紹過,這裡看一下Android中定義了13個調整級別,在ProcessList文件中
class ProcessList {
    // OOM adjustments for processes in various states:

    // This is a process without anything currently running in it.  Definitely
    // the first to go! Value set in system/rootdir/init.rc on startup.
    // This value is initalized in the constructor, careful when refering to
    // this static variable externally.
    static final int EMPTY_APP_ADJ = 15;

    // This is a process only hosting activities that are not visible,
    // so it can be killed without any disruption. Value set in
    // system/rootdir/init.rc on startup.
    static final int HIDDEN_APP_MAX_ADJ = 15;
    static int HIDDEN_APP_MIN_ADJ = 7;

    // 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 = 6;

    // This is a process holding a secondary server -- killing it will not
    // have much of an impact as far as the user is concerned. Value set in
    // system/rootdir/init.rc on startup.
    static final int SECONDARY_SERVER_ADJ = 5;

    // 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 = 4;

    // 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 = 3;

    // 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.  Value set in
    // system/rootdir/init.rc on startup.
    static final int PERCEPTIBLE_APP_ADJ = 2;

    // This is a process only hosting activities that are visible to the
    // user, so we'd prefer they don't disappear. Value set in
    // system/rootdir/init.rc on startup.
    static final int VISIBLE_APP_ADJ = 1;

    // This is the process running the current foreground app.  We'd really
    // rather not kill it! Value set in system/rootdir/init.rc on startup.
    static final int FOREGROUND_APP_ADJ = 0;

    // This is a process running a core server, such as telephony.  Definitely
    // don't want to kill it, but doing so is not completely fatal.
    static final int CORE_SERVER_ADJ = -12;

    // The system process runs at the default adjustment.
    static final int SYSTEM_ADJ = -16;
     .....
}
AMS提供了函數來改變這個值:updateOomAdjLocked
 final void updateOomAdjLocked() {
        final ActivityRecord TOP_ACT = resumedAppLocked();
        final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;

        if (false) {
            RuntimeException e = new RuntimeException();
            e.fillInStackTrace();
            Slog.i(TAG, updateOomAdj: top= + TOP_ACT, e);
        }

        mAdjSeq++;

        // Let's determine how many processes we have running vs.
        // how many slots we have for background processes; we may want
        // to put multiple processes in a slot of there are enough of
        // them.
        int numSlots = ProcessList.HIDDEN_APP_MAX_ADJ - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
        int factor = (mLruProcesses.size()-4)/numSlots;
        if (factor < 1) factor = 1;
        int step = 0;
        int numHidden = 0;
        
        // First update the OOM adjustment for each of the
        // application processes based on their current state.
        int i = mLruProcesses.size();
        int curHiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
        int numBg = 0;
        while (i > 0) {
            i--;
            ProcessRecord app = mLruProcesses.get(i);
            //Slog.i(TAG, OOM  + app + : cur hidden= + curHiddenAdj);
           
           //調用重載函數updateOomAdjLocked,更新OOM adj的值
            updateOomAdjLocked(app, curHiddenAdj, TOP_APP);
            if (curHiddenAdj < ProcessList.EMPTY_APP_ADJ
                && app.curAdj == curHiddenAdj) {
                step++;
                if (step >= factor) {
                    step = 0;
                    curHiddenAdj++;
                }
            }
            if (!app.killedBackground) {
                // 如果adj的值大於等於ProcessList.HIDDEN_APP_MIN_ADJ 
                if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
                    numHidden++;
                    if (numHidden > mProcessLimit) {
                        Slog.i(TAG, No longer want  + app.processName
                                +  (pid  + app.pid + ): hidden # + numHidden);
                        EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
                                app.processName, app.setAdj, too many background);
                        app.killedBackground = true;
                        Process.killProcessQuiet(app.pid);//殺死進程
                    } else {
                        numBg++;
                    }
                } else if (app.curAdj >= ProcessList.HOME_APP_ADJ) {
                    numBg++;
                }
            }
        }
     ......      
    }
其中調用了重載函數updateOomAdjLocked,具體代碼如下:
 private final boolean updateOomAdjLocked(ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
        app.hiddenAdj = hiddenAdj;

        if (app.thread == null) {
            return false;
        }

        final boolean wasKeeping = app.keeping;

        boolean success = true;
              
        // 1調用computeOomAdjLocked方法計算oom adj的值 
        computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);

        if (app.curRawAdj != app.setRawAdj) {
            if (false) {
                // Removing for now.  Forcing GCs is not so useful anymore
                // with Dalvik, and the new memory level hint facility is
                // better for what we need to do these days.
                if (app.curRawAdj > ProcessList.FOREGROUND_APP_ADJ
                        && app.setRawAdj <= ProcessList.FOREGROUND_APP_ADJ) {
                    // If this app is transitioning from foreground to
                    // non-foreground, have it do a gc.
                    scheduleAppGcLocked(app);
                } else if (app.curRawAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
                        && app.setRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) {
                    // Likewise do a gc when an app is moving in to the
                    // background (such as a service stopping).
                    scheduleAppGcLocked(app);
                }
            }

            if (wasKeeping && !app.keeping) {
                // This app is no longer something we want to keep.  Note
                // its current wake lock time to later know to kill it if
                // it is not behaving well.
                BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
                synchronized (stats) {
                    app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
                            app.pid, SystemClock.elapsedRealtime());
                }
                app.lastCpuTime = app.curCpuTime;
            }

            app.setRawAdj = app.curRawAdj;
        }
        if (app.curAdj != app.setAdj) {
            // 2  調用setOomAdj來修改進程的oom adj的值 
            if (Process.setOomAdj(app.pid, app.curAdj)) {
                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
                    TAG, Set app  + app.processName +
                     oom adj to  + app.curAdj +  because  + app.adjType);
                app.setAdj = app.curAdj;
            } else {
                success = false;
                Slog.w(TAG, Failed setting oom adj of  + app +  to  + app.curAdj);
            }
        }
        if (app.setSchedGroup != app.curSchedGroup) {
            app.setSchedGroup = app.curSchedGroup;
            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
                    Setting process group of  + app.processName
                    +  to  + app.curSchedGroup);
            if (app.waitingToKill != null &&
                    app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
                Slog.i(TAG, Killing  + app.toShortString() + :  + app.waitingToKill);
                EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
                        app.processName, app.setAdj, app.waitingToKill);
               // 3 調用killProcessQuiet殺死進程 
                Process.killProcessQuiet(app.pid);
                success = false;
            } else {
                if (true) {
                    long oldId = Binder.clearCallingIdentity();
                    try {
                         // 4調用setProcessGroup修改進程的調度組 
                        Process.setProcessGroup(app.pid, app.curSchedGroup);
                    } catch (Exception e) {
                        Slog.w(TAG, Failed setting process group of  + app.pid
                                +  to  + app.curSchedGroup);
                        e.printStackTrace();
                    } finally {
                        Binder.restoreCallingIdentity(oldId);
                    }
                } else {
                    if (app.thread != null) {
                        try {
                            app.thread.setSchedulingGroup(app.curSchedGroup);
                        } catch (RemoteException e) {
                        }
                    }
                }
            }
        }
        return success;
    }
函數updateOomAdjLocked,更新OOM adj的值,這一部分的主要工作有: 1.調用computeOomAdjLocked方法計算oom adj的值,這個函數比較復雜,通過一系列的運算,計算出oom adj的值 2.調用setOomAdj來修改進程的oom adj的值,這個函數就是向進程的/proc//oom_adj文件寫入計算出來的oom adj值 3.調用killProcessQuiet殺死進程 4.調用setProcessGroup修改進程的調度組 這裡主要看第三步killProcessQuiet,這個函數在Process.java文件中:
 public static final void killProcessQuiet(int pid) {
        sendSignalQuiet(pid, SIGNAL_KILL);
    }
調用了 sendSignalQuiet函數,這是一個native函數:
public static final native void sendSignalQuiet(int pid, int signal);
對應的實現在android_util_Process.cpp文件中:
void android_os_Process_sendSignalQuiet(JNIEnv* env, jobject clazz, jint pid, jint sig)
{
    if (pid > 0) {
        kill(pid, sig);//殺死進程
    }
}
到此為止進程殺死了,這種方式是直接殺死進程的方式,同樣android還提供了一個被動殺死進程的機制 Low Memory Killer機制
3 Low Memory Killer機制 這一機制的主要思想就是定義不同的oom adj級別,並為每一個級別指定最小剩余阈值。當內存中可用內存小於該阈值時,就殺死所有等於或者大於該級別的進程,這部分參看 Low Memory Killer機制



 
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved