android 소스 코드 분석 (25) -- > onLowMemory 실행 프로 세 스
여기 서 간단하게 안 드 로 이 드 시스템 의 메모리 분배 메커니즘 을 소개 합 니 다.안 드 로 이 드 시스템 에서 하나의 App 은 서로 다른 응용 프로 세 스 입 니 다. 각자 의 JVM 과 실행 을 가지 고 있 을 때 모든 App 프로 세 스 가 사용 할 수 있 는 메모리 크기 가 고정 되 어 있 습 니 다. 시스템 에서 App 을 너무 많이 열 면 안 드 로 이 드 시스템 의 사용 가능 한 메모리 가 줄 어 들 것 입 니 다. 현재 사용 하고 있 는 App 에 있어 서 시스템 메모 리 를 계속 신청 해 야 할 수도 있 습 니 다.그리고 우리 의 나머지 시스템 메모 리 는 현재 App 에 의 해 신청 되 기 에 부족 합 니 다. 이 럴 때 시스템 은 배경 프로 세 스 를 자동 으로 정리 하고 사용 가능 한 메모 리 를 풀 어 프론트 프로 세 스 의 사용 에 사용 합 니 다. 물론 이 시스템 이 배경 프로 세 스 를 청소 하 는 알고리즘 은 우리 가 토론 하 는 중심 이 아 닙 니 다.여기 서 우 리 는 안 드 로 이 드 시스템 이 Activity 를 되 돌 리 는 onLowMemory 방법 을 대충 분석 하 는 절차 일 뿐이다.
앞에서 Activity 에 대한 시작 프로 세 스 분석 을 통 해 알 수 있 듯 이 Activity Manager Service 는 전체 안 드 로 이 드 시스템 의 관리 중추 이 고 Activity, Servier 등 4 대 구성 요소 의 시작 과 소각 등 업 무 를 담당 하 며 똑 같이 응용 프로 세 스에 대한 관리 업무 도 Activity Maanger Servier 에서 이 루어 졌 다.안 드 로 이 드 시스템 에는 두 개의 중요 한 프로 세 스 가 있 습 니 다. Zygote 프로 세 스 와 SystemServer 프로 세 스 가 있 습 니 다. 그 중에서 Zygote 프로 세 스 는 전체 안 드 로 이 드 시스템 의 루트 프로 세 스 이 고 다른 모든 프로 세 스 는 Zygote 프로 세 스 fork 를 통 해 나 왔 습 니 다.한편, SystemServer 프로 세 스 는 각종 서 비 스 를 실행 하고 다른 응용 프로 세 스에 각종 기능 인 터 페 이 스 를 제공 하 는 데 사 용 됩 니 다. 앞에서 SystemServer 프로 세 스 의 시작 프로 세 스 를 분 석 했 습 니 다 (참고:http://blog.csdn.net/qq_23547831/article/details/51105171) 그 중에서 SystemServer 의 startBootService 방법 에서 다음 과 같이 호출 되 었 습 니 다.
// Set up the Application instance for the system process and get started. mActivityManagerService.setSystemProcess();
방법, 설명 을 보십시오. System 프로 세 스 를 위 한 응용 프로그램 인 스 턴 스 를 초기 화 하 는 것 입 니 다. 이 방법의 구체 적 인 실현 을 볼 수 있 습 니 다.
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);
}
}
여기 서 간단하게 Servier Manager 는 서 비 스 를 관리 하 는 서비스 이 고 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 가 있 습 니 다. 이 방법 은 주로 셸 명령 을 수행 하 는 데 사 용 됩 니 다. 시스템 이 메모리 가 비교적 낮 을 때 이 방법 을 실 행 했 습 니 다. 그 다음 에 Activity Manager Service 의 kill AllBackground 방법 으로 되 돌 립 니 다.다음은 kill AllBackground 방법의 구체 적 인 실현 에 중점 을 두 고 살 펴 보 겠 습 니 다.
@Override
public void killAllBackgroundProcesses() {
...
doLowMemReportIfNeededLocked(null);
...
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
이 방법 체 에서 doLowMemReportIfNeeded Locked 방법 이 실 행 됩 니 다. 이 방법 은 무엇 을 하 는 것 입 니까?doLowMemReportIfNeeded Locked 방법의 실현 을 계속 살 펴 보 겠 습 니 다.
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 의 handle Message 방법 에서 msg 의 what 가 GC 인지 먼저 판단 합 니 다.BACKGROUND_PROCESSES_MSG, 그리고 permAppGcsIf AppropriateLocked 방법 을 실행 합 니 다. 그러면 permAppGcsIf AppropriateLocked 방법의 실현 을 계속 살 펴 보 겠 습 니 다.
/** * 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 일 때 까지 permAppGcsLocked 방법 을 실행 한 다음 return 을 실행 합 니 다. 그러면 우 리 는 코드 를 계속 추적 하여 permAppGcsLocked 방법의 실행 논 리 를 볼 수 있 습 니 다.
/** * 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();
}
}
이 방법 은 일련의 논리 적 판단 을 거 친 후에 performaAppGCLocked 방법 을 실행 할 것 임 을 알 수 있 습 니 다. 우 리 는 이 방법의 실현 을 계속 살 펴 보 겠 습 니 다.
/** * 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 는 Activity Thread. ApplicationThread 대상 이기 때문에 여 기 는 최종 적 으로 Binder 프로 세 스 간 통신 을 통 해 Activity Thread. ApplicationThread 의 scheduleLowMemory 방법 을 실 행 했 습 니 다.그래 요. Activity Thread. applicationThread 의 scheduleLowMemory 방법의 실현 논 리 를...
@Override
public void scheduleLowMemory() {
sendMessage(H.LOW_MEMORY, null);
}
Activity Thread 의 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 의 handle Message 방법 에서 최종 적 으로 handle LowMemory 방법 을 호출 한 것 을 알 수 있 습 니 다.
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();
}
// 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();
EventLog.writeEvent(SQLITE_MEM_RELEASED_EVENT_LOG_TAG, sqliteReleased);
}
// Ask graphics to free up as much as possible (font/image caches)
Canvas.freeCaches();
// Ask text layout engine to free also as much as possible
Canvas.freeTextLayoutCaches();
BinderInternal.forceGc("mem");
}
ComponentCallbacks 2 를 옮 겨 다 니 며 onLowMemory 방법 을 실행 한 것 을 발견 할 수 있 습 니 다. 그러면 이곳 의 ComponentCallBacks 2 는 무엇 입 니까?collectComponentCallbacks 방법의 실현 논 리 를 살 펴 보 겠 습 니 다.
ArrayList<ComponentCallbacks2> collectComponentCallbacks(
boolean allActivities, Configuration newConfig) {
ArrayList<ComponentCallbacks2> callbacks
= new ArrayList<ComponentCallbacks2>();
synchronized (mResourcesManager) {
final int NAPP = mAllApplications.size();
for (int i=0; i<NAPP; i++) {
callbacks.add(mAllApplications.get(i));
}
final int NACT = mActivities.size();
for (int i=0; i<NACT; i++) {
ActivityClientRecord ar = mActivities.valueAt(i);
Activity a = ar.activity;
if (a != null) {
Configuration thisConfig = applyConfigCompatMainThread(
mCurDefaultDisplayDpi, newConfig,
ar.packageInfo.getCompatibilityInfo());
if (!ar.activity.mFinished && (allActivities || !ar.paused)) {
// If the activity is currently resumed, its configuration
// needs to change right now.
callbacks.add(a);
} else if (thisConfig != null) {
// Otherwise, we will tell it about the change
// the next time it is resumed or shown. Note that
// the activity manager may, before then, decide the
// activity needs to be destroyed to handle its new
// configuration.
if (DEBUG_CONFIGURATION) {
Slog.v(TAG, "Setting activity "
+ ar.activityInfo.name + " newConfig=" + thisConfig);
}
ar.newConfig = thisConfig;
}
}
}
final int NSVC = mServices.size();
for (int i=0; i<NSVC; i++) {
callbacks.add(mServices.valueAt(i));
}
}
synchronized (mProviderMap) {
final int NPRV = mLocalProviders.size();
for (int i=0; i<NPRV; i++) {
callbacks.add(mLocalProviders.valueAt(i).mLocalProvider);
}
}
return callbacks;
}
이 방법 은 최종 적 으로 ArrayList 형식의 callBacks 로 되 돌아 가 는 것 을 발견 할 수 있 습 니 다. 우리 의 callBacks 에는 우리 응용 프로 세 스 의 Activity, Service, Provider 가 이미 Application 등 을 저장 하고 있 습 니 다.어?Activity, Service, Provider, Application 은 모두 ComponentCallBacks 2 유형 입 니까?구체 적 인 정 의 를 살 펴 보 자.
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
응용 프로그램의 클래스 정의:
public class Application extends ContextWrapper implements ComponentCallbacks2
모두 계승 과 ComponentCalbacks 2 를 발견 할 수 있 기 때문에 모두 ComponentCallbacks 2 유형의 변수 로 여 겨 질 수 있다.같은 4 대 구성 요소 인 BroadcastReceiver 는 다음 과 같은 정 의 를 내 릴 수 있 습 니 다.
public abstract class BroadcastReceiver
ComponentCallbacks 2 와 계승 되 지 않 았 기 때문에 실행 되 지 않 았 음 을 알 수 있 습 니 다. 그래서 이러한 분석 을 통 해 우 리 는 최종 응용 프로그램의 Activity, Servier, ContentProvider, Application 의 onLowMemory 방법 이 실 행 될 것 이라는 것 을 알 게 되 었 습 니 다.한편, 우 리 는 시스템 메모리 가 부족 할 때 kill AllBackground 방법 을 실행 하고 Activity, Service, ContentProvider, Application 의 onLowMemory 방법 을 여러 겹 으로 실행 하기 때문에 우 리 는 이 구성 요소 들 의 onLowMemory 방법 에서 자원 을 정리 하 는 작업 을 수행 하고 메모 리 를 방출 하여 자신의 응용 프로 세 스 가 죽 이지 않도록 할 수 있 습 니 다.
요약:
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.