Android 操作系统中的内存回收

原文:https://blog.csdn.net/anlike/article/details/77749833 

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 将所有此类进程全部杀死
--------------------- 

 

阅读更多

没有更多推荐了,返回首页