Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android源碼解析(二十五)--)onLowMemory執行流程

android源碼解析(二十五)--)onLowMemory執行流程

編輯:關於Android編程

上篇文章中我們分析了Activity的onSaveInstanceState方法執行時機,知道了Activity在一般情況下,若只是執行onPause方法則不會執行onSaveInstanceState方法,而一旦執行了onStop方法就會執行onSaveInstanceState方法,這篇文章中同樣的我們分析一下Actvity(當然不只是Activity,同樣包含Servier,ContentProvider,Application等)的另一個內部方法:onLowMemory。該方法主要用於當前系統可用內存比較低的時候回調使用。

這裡簡單介紹一下Android系統的內存分配機制。Android系統中一個個的App都是一個個不同的應用進程,擁有各自的JVM與運行時,每個App的進程可使用的內存大小都是固定的,當系統中App打開數量過多時,就會使Android系統的可用內存降低,對於當前正在使用的App而言,可能還需要繼續申請系統內存,而我們的剩余系統內存已經不足以被當前App所申請了,這時候系統會自動的清理那些後台進程,進而釋放出可用內存用於前台進程的使用,當然這裡系統清理後台進程的算法不是我們討論的重點。這裡我們只是大概的分析Android系統回調Activity的onLowMemory方法的流程。

通過前面關於Activity的啟動流程分析我們知道ActivityManagerService是整個Android系統的管理中樞,負責Activity,Servier等四大組件的啟動與銷毀等工作,同樣的對於應用進程的管理工作也是在ActivityMaangerServier中完成的,我們知道android系統中有兩個比較重要的進程Zygote進程和SystemServer進程,其中Zygote進程是整個Android系統的根進程,其他所有的進程都是通過Zygote進程fork出來的。而SystemServer進程則用於運行各種服務,為其他的應用進程提供各種功能接口等,在前面我們分析過SystemServer進程的啟動流程,其中在SystemServer的startBootService方法中我們調用了:

// Set up the Application instance for the system process and get started.
        mActivityManagerService.setSystemProcess();

方法,看其注釋說明,說的是為System進程初始化Application實例,這裡我們可以看一下該方法的具體實現:

public void setSystemProcess() {
        try {
            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
            ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
            ServiceManager.addService("meminfo", new MemBinder(this));
            ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
            ServiceManager.addService("dbinfo", new DbBinder(this));
            if (MONITOR_CPU_USAGE) {
                ServiceManager.addService("cpuinfo", new CpuBinder(this));
            }
            ServiceManager.addService("permission", new PermissionController(this));
            ServiceManager.addService("processinfo", new ProcessInfoService(this));

            ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
                    "android", STOCK_PM_FLAGS);
            mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());

            synchronized (this) {
                ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
                app.persistent = true;
                app.pid = MY_PID;
                app.maxAdj = ProcessList.SYSTEM_ADJ;
                app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
                synchronized (mPidsSelfLocked) {
                    mPidsSelfLocked.put(app.pid, app);
                }
                updateLruProcessLocked(app, false, null);
                updateOomAdjLocked();
            }
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(
                    "Unable to find android system package", e);
        }
    }

這裡簡單介紹一下ServierManager是一個管理服務的服務,而其addServier方法就是注冊各種服務(服務注冊到JNI層,具體的關於是如何注冊到JNI層的這裡暫不做過多的解釋)。可以發現在方法體中我們注冊了名稱為:memInfo的服務MemBinder,MemBinder是一個Binder類型的服務,主要用於檢測系統內存情況,這裡可以看一下其具體的實現邏輯:

static class MemBinder extends Binder {
        ActivityManagerService mActivityManagerService;
        MemBinder(ActivityManagerService activityManagerService) {
            mActivityManagerService = activityManagerService;
        }

        @Override
        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            if (mActivityManagerService.checkCallingPermission(android.Manifest.permission.DUMP)
                    != PackageManager.PERMISSION_GRANTED) {
                pw.println("Permission Denial: can't dump meminfo from from pid="
                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
                        + " without permission " + android.Manifest.permission.DUMP);
                return;
            }

            mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, "  ", args, false, null);
        }
    }

查看源碼,我們可以發現MemBinder類繼承於Binder類也就是說其實一個Binder類型的服務,並且有一個成員方法dump,該方法主要用於執行shell命令,當系統可用內存比較低的時候就會執行了該方法,然後回調到ActivityManagerService中的killAllBackground方法,下面我們重點看一下killAllBackground方法的具體實現:

@Override
    public void killAllBackgroundProcesses() {
        ...
           doLowMemReportIfNeededLocked(null);
        ...
        } finally {
            Binder.restoreCallingIdentity(callingId);
        }
    }

可以看到這個方法體中會執行doLowMemReportIfNeededLocked方法,該方法是做什麼的呢?我們繼續看一下doLowMemReportIfNeededLoced方法的實現:

final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
        ...
        scheduleAppGcsLocked();
        ...
    }

好吧,在這個方法中我們又調用了scheduleAppGcsLocked方法,這樣我們就繼續看一下scheduleAppGcsLocked方法的實現邏輯:

/**
     * Schedule the execution of all pending app GCs.
     */
    final void scheduleAppGcsLocked() {
        mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);

        if (mProcessesToGc.size() > 0) {
            // Schedule a GC for the time to the next process.
            ProcessRecord proc = mProcessesToGc.get(0);
            Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);

            long when = proc.lastRequestedGc + GC_MIN_INTERVAL;
            long now = SystemClock.uptimeMillis();
            if (when < (now+GC_TIMEOUT)) {
                when = now + GC_TIMEOUT;
            }
            mHandler.sendMessageAtTime(msg, when);
        }
    }

可以發現這裡執行的邏輯就是通過mHandler發送一個msg.what為GC_BACKGROUND_PROCESSES_MSG的異步消息,這樣消息體最終會被mHandler的handleMessage方法所執行,繼續看一下mHandler的handleMessage方法的執行邏輯:

case GC_BACKGROUND_PROCESSES_MSG: {
                synchronized (ActivityManagerService.this) {
                    performAppGcsIfAppropriateLocked();
                }
            } break;

在mHandler的handleMessage方法中,首先會判斷msg的what是否為GC_BACKGROUND_PROCESSES_MSG,然後會執行performAppGcsIfAppropriateLocked方法,這樣我們繼續看一下performAppGcsIfAppropriateLocked方法的實現:

/**
     * If all looks good, perform GCs on all processes waiting for them.
     */
    final void performAppGcsIfAppropriateLocked() {
        if (canGcNowLocked()) {
            performAppGcsLocked();
            return;
        }
        // Still not idle, wait some more.
        scheduleAppGcsLocked();
    }

可以發現這裡首先判斷是否能夠執行gc操作,若不能繼續執行上面的scheduleAppGcsLocked方法,然後繼續執行發送異步消息的邏輯,直到變量canGcNowLocked為true,並執行performAppGcsLocked方法,然後return掉,這樣我們繼續跟蹤代碼,看一下performAppGcsLocked方法的執行邏輯:

/**
     * Perform GCs on all processes that are waiting for it, but only
     * if things are idle.
     */
    final void performAppGcsLocked() {
        final int N = mProcessesToGc.size();
        if (N <= 0) {
            return;
        }
        if (canGcNowLocked()) {
            while (mProcessesToGc.size() > 0) {
                ProcessRecord proc = mProcessesToGc.remove(0);
                if (proc.curRawAdj > ProcessList.PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
                    if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
                            <= SystemClock.uptimeMillis()) {
                        // To avoid spamming the system, we will GC processes one
                        // at a time, waiting a few seconds between each.
                        performAppGcLocked(proc);
                        scheduleAppGcsLocked();
                        return;
                    } else {
                        // It hasn't been long enough since we last GCed this
                        // process...  put it in the list to wait for its time.
                        addProcessToGcListLocked(proc);
                        break;
                    }
                }
            }

            scheduleAppGcsLocked();
        }
    }

可以發現該方法經過一系列的邏輯判斷之後會執行performAppGcLocked方法,我們繼續看一下該方法的實現:

/**
     * Ask a given process to GC right now.
     */
    final void performAppGcLocked(ProcessRecord app) {
        try {
            app.lastRequestedGc = SystemClock.uptimeMillis();
            if (app.thread != null) {
                if (app.reportLowMemory) {
                    app.reportLowMemory = false;
                    app.thread.scheduleLowMemory();
                } else {
                    app.thread.processInBackground();
                }
            }
        } catch (Exception e) {
            // whatever.
        }
    }

可以發現最終執行的是app.thread.scheduleLowMemory方法,而這裡的app.thread是ActivityThread.ApplicationThread對象,所以這裡最終是通過Binder進程間通訊,執行的是ActivityThread.ApplicationThread的scheduleLowMemory方法,好吧讓我們看一下ActivityThread.ApplicationThread的scheduleLowMemory
方法的實現邏輯…

@Override
        public void scheduleLowMemory() {
            sendMessage(H.LOW_MEMORY, null);
        }

在ActivityThread中的scheduleLowMemory方法中並沒有執行額外邏輯,而是直接調用了sendMessage方法,繼續跟蹤方法的執行:

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }

可以發現在sendMessage方法中最終通過一個Handler類型的mH成員變量發送一個異步消息,這樣異步消息最終會被mH的handleMessage方法執行。。。。,經過查看源代碼我們知道在mH的handleMessage方法中最終調用的是handleLowMemory方法:

final void handleLowMemory() {
        ArrayList callbacks = collectComponentCallbacks(true, null);

        final int N = callbacks.size();
        for (int i=0; i

可以發現這裡通過遍歷ComponentCallbacks2並執行了其onLowMemory方法,那麼這裡的ComponentCallBacks2是什麼呢?這裡我們查看一下collectComponentCallbacks方法的實現邏輯。

ArrayList collectComponentCallbacks(
            boolean allActivities, Configuration newConfig) {
        ArrayList callbacks
                = new ArrayList();

        synchronized (mResourcesManager) {
            final int NAPP = mAllApplications.size();
            for (int i=0; i

可以發現該方法最終返回類型為ArrayList類型的callBacks而我們的callBacks中保存的是我們應用進程中的Activity,Service,Provider已經Application等。咦?Activity,Service,Provider,Application都是ComponentCallBacks2類型的麼?我們看一看一下具體的定義:

Actvity的類定義:

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback

Service的類定義:

public abstract class Service extends ContextWrapper implements ComponentCallbacks2

ContentProvider的類定義:

public abstract class ContentProvider implements ComponentCallbacks2

Application的類定義:

public class Application extends ContextWrapper implements ComponentCallbacks2

可以發現其都是繼承與ComponentCalbacks2,所以其都可以被當做是ComponentCallbacks2類型的變量。而同樣是四大組件的BroadcastReceiver,我們可以下其類定義:

public abstract class BroadcastReceiver

可以看到其並未繼承與ComponentCallbacks2,所以並未執行,所以通過這樣的分析,我們知道了,最終應用程序中的Activity,Servier,ContentProvider,Application的onLowMemory方法會被執行。而由於我們是在系統內存緊張的時候會執行killAllBackground方法進而通過層層條用執行Activity、Service、ContentProvider、Application的onLowMemory方法,所以我們可以在這些組件的onLowMemory方法中執行了一些清理資源的操作,釋放一些內存,盡量保證自身的應用進程不被殺死。

總結:

系統在JNI層會時時檢測內存變量,當內存過低時會通過kiilbackground的方法清理後台進程。

經過層層的調用過程最終會執行Activity、Service、ContentProvider、Application的onLowMemory方法。

可以在組件的onLowMemory方法中執行一些清理資源的操作,釋放內存防止進程被殺死。

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