Android 操作系统中的内存回收

xiaoxiao2021-02-28  44

Android 系统中内存回收的触发点大致可分为三种情况: 第一种情况 用户程序调用 StartActivity(), 使当前活动的 Activity 被覆盖 第二种情况 :按下Back键,会调用finishActivityLocked,然后把Activity的finishing标志设为true,然后再调用startPausingLocked,当目标actiity完成暂停后,就会通知Ams,此时Ams从completePaused开始执行,由于此时暂停的Activity的finising状态已经变为true,所以会执行finishingActivtyLocked。 第三种情况 启动一个新的应用程序 。向Ams发送一个Idle消息,这会导致Ams开始执行activityIdleInternal方法,该方法首先处理mStoppingActivities中的对象,接着处理mFinishingActivities列表,然后再调用trimApplications 这些能够触发内存回收的事件最终调用的函数接口就是 activityIdleInternalLocked(). 1.当 ActivityManagerService 接收到异步消息 DLE_NOW_MSG 时 将会被调用。 2.当 ActivityManagerService 接收到异步消息 IDLE_TIMEOUT_MSG 时将会被调用。 3.ActivityManagerService.的activityIdle中将会被调用 一, 1.IDLE_NOW_MSG 由 Activity 的切换以及 Activiy 焦点的改变等事件引发. 2.IDLE_TIMEOUT_MSG 在 Activity 启动超时的情况下引发,一般这个超时时间设为 10s,如果 10s 之内一个 Activity 依然没有成功启动,那么将发送异步消息 IDLE_TIMEOUT_MSG 进行资源回收。 文件路径: Z:\HLOS\frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java private final class ActivityStackSupervisorHandler extends Handler { 。。。。。。。。。 void activityIdleInternal(ActivityRecord r) { synchronized (mService) { activityIdleInternalLocked(r != null ? r.appToken : null, true, null); } } @Override public void handleMessage(Message msg) { switch (msg.what) { ....... case IDLE_TIMEOUT_MSG: { if (DEBUG_IDLE) Slog.d(TAG_IDLE, "handleMessage: IDLE_TIMEOUT_MSG: r=" + msg.obj); if (mService.mDidDexOpt) { mService.mDidDexOpt = false; Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG); nmsg.obj = msg.obj; mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT); return; } // We don't at this point know if the activity is fullscreen, // so we need to be conservative and assume it isn't. activityIdleInternal((ActivityRecord)msg.obj); } break; case IDLE_NOW_MSG: { if (DEBUG_IDLE) Slog.d(TAG_IDLE, "handleMessage: IDLE_NOW_MSG: r=" + msg.obj); activityIdleInternal((ActivityRecord)msg.obj); } break; } } 3.activityIdle是在handleResumeActivity添加一个空闲任务,然后在looper线程空闲的时候调用 Z:\HLOS\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java @Override public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) { final long origId = Binder.clearCallingIdentity(); synchronized (this) { ActivityStack stack = ActivityRecord.getStackLocked(token); if (stack != null) { ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token, false, config); if (stopProfiling) { if ((mProfileProc == r.app) && (mProfileFd != null)) { try { mProfileFd.close(); } catch (IOException e) { } clearProfilerLocked(); } } } } Binder.restoreCallingIdentity(origId); } 主要就是检测当前activity栈是否为空,如果栈中有activity,那么就调用ActivityStactSupervisor. activityIdleInternalLocked方法 Z:\HLOS\frameworks\base\core\java\android\app\ActivityThread.java 调用ActivityManagerService的activityIdle方法在ActivityThread的内部handler Idler中。 private class Idler implements MessageQueue.IdleHandler { @Override public final boolean queueIdle() { ActivityClientRecord a = mNewActivities; boolean stopProfiling = false; if (mBoundApplication != null && mProfiler.profileFd != null && mProfiler.autoStopProfiler) { stopProfiling = true; } if (a != null) { mNewActivities = null; IActivityManager am = ActivityManagerNative.getDefault(); ActivityClientRecord prev; do { if (localLOGV) Slog.v( TAG, "Reporting idle of " + a + " finished=" + (a.activity != null && a.activity.mFinished)); if (a.activity != null && !a.activity.mFinished) { try { am.activityIdle(a.token, a.createdConfig, stopProfiling); a.createdConfig = null; } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } prev = a; a = a.nextIdle; prev.nextIdle = null; } while (a != null); } if (stopProfiling) { mProfiler.stopProfiling(); } ensureJitEnabled(); return false; } } 这是Message队列的内部类闲置handler,这个queueIdle回调在消息队列中没有消息可以处理的空闲时期被调起,此前已经分析过了。 queueIdle() return true ,表示保留,当queueIdle执行完毕之后,不会移除这个IdleHandler return false ,表示这个IdleHandler不需要保留,也就是只需要执行一遍。 接着应该看 Looper.myQueue().addIdleHandler()什么时候把 Idler 添加进去的了 final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) { ActivityClientRecord r = mActivities.get(token); .............. if (!r.onlyLocalRequest) { r.nextIdle = mNewActivities; mNewActivities = r; if (localLOGV) Slog.v( TAG, "Scheduling idle handler for " + r); Looper.myQueue().addIdleHandler(new Idler()); } r.onlyLocalRequest = false; // Tell the activity manager we have resumed. if (reallyResume) { try { ActivityManagerNative.getDefault().activityResumed(token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } } else { // If an exception was thrown when trying to resume, then // just end this activity. try { ActivityManagerNative.getDefault() .finishActivity(token, Activity.RESULT_CANCELED, null, Activity.DONT_FINISH_TASK_WITH_ACTIVITY); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } } 也就是说,在activity执行resume方法之后,系统会在当前的线程中添加一个空闲任务。 这边需要科普一下,一般我们在调用了finish方法,或者是启动了一个新的应用或者是activity方法之后,当前的activity会处于后台,并且处于空闲,因此就会触发queueIdle的方法,从而触发AMS的activityIdle的方法。 二, 现在我们可以主要分析 activityIdleInternalLocked方法了 Z:\HLOS\frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout, Configuration config) { if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + token); ArrayList<ActivityRecord> finishes = null; ArrayList<UserState> startingUsers = null; int NS = 0; int NF = 0; boolean booting = false; boolean activityRemoved = false; ActivityRecord r = ActivityRecord.forTokenLocked(token); if (r != null) { if (DEBUG_IDLE) Slog.d(TAG_IDLE, "activityIdleInternalLocked: Callers=" + Debug.getCallers(4)); mHandler.removeMessages(IDLE_TIMEOUT_MSG, r); r.finishLaunchTickingLocked(); if (fromTimeout) { reportActivityLaunchedLocked(fromTimeout, r, -1, -1); } // This is a hack to semi-deal with a race condition // in the client where it can be constructed with a // newer configuration from when we asked it to launch. // We'll update with whatever configuration it now says // it used to launch. if (config != null) { r.configuration = config; } // We are now idle. If someone is waiting for a thumbnail from // us, we can now deliver. r.idle = true; //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout); if (isFocusedStack(r.task.stack) || fromTimeout) { booting = checkFinishBootingLocked(); } } //1.通知所有需要内存回收的进程进行内存回收(这些进程都保存在mProgressToGc列表中) if (allResumedActivitiesIdle()) { if (r != null) { mService.scheduleAppGcsLocked(); } if (mLaunchingActivity.isHeld()) { mHandler.removeMessages(LAUNCH_TIMEOUT_MSG); if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) { throw new IllegalStateException("Calling must be system uid"); } mLaunchingActivity.release(); } ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); } 2. 分别拿到所有要stop和finish的activity存放在stops和finishs容器中,然后将记录清空 // Atomically retrieve all of the other things to do. // 获取已经暂停的activity列表 final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(true); NS = stops != null ? stops.size() : 0; if ((NF = mFinishingActivities.size()) > 0) { // 获取已经触发了finish方法的列表 finishes = new ArrayList<>(mFinishingActivities); mFinishingActivities.clear(); } if (mStartingUsers.size() > 0) { startingUsers = new ArrayList<>(mStartingUsers); mStartingUsers.clear(); } // Stop any activities that are scheduled to do so but have been // waiting for the next one to start. for (int i = 0; i < NS; i++) { r = stops.get(i); final ActivityStack stack = r.task.stack; if (stack != null) { //如果该被暂停的activity已经调用了finish方法,那么就调用栈的finish当前的activity的方法 if (r.finishing) { stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false); } else { // 否则调用栈的stopActivity方法 stack.stopActivityLocked(r); } } } // Finish any activities that are scheduled to do so but have been // waiting for the next one to start. // 遍历finish列表中的每一个activity,如果当前栈不为空,就去触发栈的destroyActivityLocked方法 for (int i = 0; i < NF; i++) { r = finishes.get(i); final ActivityStack stack = r.task.stack; if (stack != null) { activityRemoved |= stack.destroyActivityLocked(r, true, "finish-idle"); //并没有真正意义上改变内存的使用,只是将其状态改变为“允许回收”,真正的回收在下面即将调用的 trimApplications() 函数中 } } if (!booting) { // Complete user switch if (startingUsers != null) { for (int i = 0; i < startingUsers.size(); i++) { mService.mUserController.finishUserSwitch(startingUsers.get(i)); } } } mService.trimApplications(); //真正开始杀进程回收 //dump(); //mWindowManager.dump(); if (activityRemoved) { resumeFocusedStackTopActivityLocked(); //删除成功后恢复焦点堆栈activity的显示 } return r; } 一、 scheduleAppGcsLocked()分析//通知各进程要GC Z:\HLOS\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java /** * Schedule the execution of all pending app GCs. */ final void scheduleAppGcsLocked() { mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG); //从mProcessesToGc列表中取出下一个ProcessRecord ,并发送一个延迟消息,由performAppGcsIfAppropriateLocked()来执行 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); } } final class MainHandler extends Handler { ...... case GC_BACKGROUND_PROCESSES_MSG: { synchronized (ActivityManagerService.this) { performAppGcsIfAppropriateLocked(); } } break; ...... } /** * 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(); } /** * Returns true if things are idle enough to perform GCs. */ //判断是否足够闲置可以来执行GC private final boolean canGcNowLocked() { boolean processingBroadcasts = false; for (BroadcastQueue q : mBroadcastQueues) { if (q.mParallelBroadcasts.size() != 0 || q.mOrderedBroadcasts.size() != 0) { processingBroadcasts = true; } } return !processingBroadcasts && (isSleepingLocked() || mStackSupervisor. allResumedActivitiesIdle()); } Z:\HLOS\frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java boolean allResumedActivitiesIdle() { for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = stacks.get(stackNdx); if (!isFocusedStack(stack) || stack.numActivities() == 0) { continue; } final ActivityRecord resumedActivity = stack.mResumedActivity; if (resumedActivity == null || !resumedActivity.idle) { if (DEBUG_STATES) Slog.d(TAG_STATES, "allResumedActivitiesIdle: stack=" + stack.mStackId + " " + resumedActivity + " not idle"); return false; } } } // Send launch end powerhint when idle mService.mActivityStarter.sendPowerHintForLaunchEndIfNeeded(); return true; } /** * 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); //在mProcessesToGc列表中逐个取出每个需要进行gc的ProcessRecord对象,同时移除 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. //如果超过了最小时间间隔,则从mProcessesToGc列表中取出下一个app,并发送一个延迟消息 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. //先检查app上一次进行gc的时间,并和当前时间进行对比,如果还没超过最小间隔,则将指定的app 加入到mProcessesToGc列表中 addProcessToGcListLocked(proc); break; } } } scheduleAppGcsLocked(); } } /** * 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. } } Z:\HLOS\frameworks\base\core\java\android\app\ActivityThread.java @Override public void scheduleLowMemory() { sendMessage(H.LOW_MEMORY, null); } public void processInBackground() { mH.removeMessages(H.GC_WHEN_IDLE); mH.sendMessage(mH.obtainMessage(H.GC_WHEN_IDLE)); } private class H extends Handler { ...... case LOW_MEMORY: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "lowMemory"); handleLowMemory(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; case GC_WHEN_IDLE: scheduleGcIdler(); break; ....... } final void handleLowMemory() { ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null); final int N = callbacks.size(); for (int i=0; i<N; i++) { callbacks.get(i).onLowMemory(); //回调该进程所包含的所有组件的onLowMemory方法 } // Ask SQLite to free up as much memory as it can, mostly from its page caches. if (Process.myUid() != Process.SYSTEM_UID) { int sqliteReleased = SQLiteDatabase.releaseMemory(); / /不是SYSTEM_UID就释放SQLite模块占用的内存。 EventLog.writeEvent(SQLITE_MEM_RELEASED_EVENT_LOG_TAG, sqliteReleased); } // Ask graphics to free up as much as possible (font/image caches) Canvas.freeCaches(); //释放应用中所有的canvas对象 // Ask text layout engine to free also as much as possible Canvas.freeTextLayoutCaches();/ /释放应用中所有的Text Layout BinderInternal.forceGc("mem"); //释放该进程的Binder对象 } void scheduleGcIdler() { if (!mGcIdlerScheduled) { mGcIdlerScheduled = true; Looper.myQueue().addIdleHandler(mGcIdler); //正常GC都是任务空闲时执行 } mH.removeMessages(H.GC_WHEN_IDLE); } final class GcIdler implements MessageQueue.IdleHandler { @Override public final boolean queueIdle() { doGcIfNeeded(); return false; } } MIN_TIME_BETWEEN_GCS = 5*1000; void doGcIfNeeded() { mGcIdlerScheduled = false; final long now = SystemClock.uptimeMillis(); //Slog.i(TAG, "**** WE MIGHT WANT TO GC: then=" + Binder.getLastGcTime() // + "m now=" + now); if ((BinderInternal.getLastGcTime()+ MIN_TIME_BETWEEN_GCS) < now) { //两次GC间隔不能小于5S //Slog.i(TAG, "**** WE DO, WE DO WANT TO GC!"); BinderInternal.forceGc("bg"); //释放该进程的Binder对象 } } Z:\HLOS\frameworks\base\core\java\com\android\internal\os\BinderInternal.java public static void forceGc(String reason) { EventLog.writeEvent(2741, reason); VMRuntime.getRuntime().requestConcurrentGC(); //虚拟机GC } 二、 trimApplications()分析 //真正回收内存 final void trimApplications() { synchronized (this) { int i; // First remove any unused application processes whose package // has been removed. for (i=mRemovedProcesses.size()-1; i>=0; i--) { final ProcessRecord app = mRemovedProcesses.get(i); //1.必须是空进程,即进程中没有任何 activity 存在。如果杀死存在 Activity 的进程,有可能关闭用户正在使用的程序,或者使应用程序恢复的时延变大,从而影响用户体验; //2.必须无 broadcast receiver。运行 broadcast receiver 一般都在等待一个事件的发生,用户并不希望此类程序被系统强制关闭; //3.进程中 service 的数量必须为 0。存在 service 的进程很有可能在为一个或者多个程序提供某种服务,如 GPS 定位服务。杀死此类进程将使其他进程无法正常服务 if (app.activities.size() == 0 && app.curReceiver == null && app.services.size() == 0) { Slog.i( TAG, "Exiting empty application process " + app.toShortString() + " (" + (app.thread != null ? app.thread.asBinder() : null) + ")\n"); if (app.pid > 0 && app.pid != MY_PID) { app.kill("empty", false); } else { try { app.thread.scheduleExit(); //pid为0说明已经杀过了,pid==MY_PID说明是当前system进程 } catch (Exception e) { // Ignore exceptions. } } cleanUpApplicationRecordLocked(app, false, true, -1, false /*replacingPid*/); mRemovedProcesses.remove(i); if (app.persistent) { addAppLocked(app.info, false, null /* ABI override */); } } } // Now update the oom adj for all processes. updateOomAdjLocked(); } } Z:\HLOS\frameworks\base\core\java\android\app\ActivityThread.java public final void scheduleExit() { sendMessage(H.EXIT_APPLICATION, null); } private class H extends Handler { ...... case EXIT_APPLICATION: if (mInitialApplication != null) { mInitialApplication.onTerminate(); //This method is for use in emulated process environments } Looper.myLooper().quit(); / /退出 break; ...... } Z:\HLOS\frameworks\base\services\core\java\com\android\server\am\ProcessRecord.java void kill(String reason, boolean noisy) { if (!killedByAm) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill"); if (noisy) { Slog.i(TAG, "Killing " + toShortString() + " (adj " + setAdj + "): " + reason); } if(toShortString().contains("com.android.dialer")||toShortString().contains("com.android.server.telecom")){ Slog.i(TAG, "Killing return leihujun dialer"); return; } EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason); Process.killProcessQuiet(pid); ActivityManagerService.killProcessGroup(uid, pid); if (!persistent) { killed = true; killedByAm = true; } Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } } 1.mRemovedProcesses 列表中主要包含了 crash 的进程、5 秒内没有响应并被用户选在强制关闭的进程、以及应用开发这调用 killBackgroundProcess 想要杀死的进程。调用 Process.killProcess 将所有此类进程全部杀死
转载请注明原文地址: https://www.6miu.com/read-45951.html

最新回复(0)