当前位置:网站首页>Analysis of Andriod low on memory printing principle
Analysis of Andriod low on memory printing principle
2022-07-28 12:59:00 【Private dishes】
The source code is based on :Android R
0. Preface
02-09 17:15:20.886446 1164 13478 I ActivityManager: Low on memory:
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 986102: [email protected]_64 (pid 389) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 54670: logd (pid 261) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 17231: surfaceflinger (pid 421) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 10194: zygote (pid 367) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 10051: webview_zygote (pid 1696) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 9442: qcrild (pid 716) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 8538: qcrild (pid 681) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 7767: cameraserver (pid 578) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 7081: audioserver (pid 418) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 6399: mediaserver (pid 647) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 6032: zygote64 (pid 366) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 5666: netmgrd (pid 673) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 4992: media.metrics (pid 645) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 4738: media.swcodec (pid 678) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 4687: init (pid 1) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 4634: [email protected] (pid 393) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 4579: android.hardware.audio.service (pid 386) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 4565: media.extractor (pid 637) native
02-09 17:15:20.887069 1164 13478 I ActivityManager: ntv ?? 4131: imsdaemon (pid 668) native
...
02-09 17:15:20.887217 1164 13478 I ActivityManager: vis IMPF 7024: com.android.smspush (pid 2446) service
02-09 17:15:20.887217 1164 13478 I ActivityManager: com.android.smspush/.WapPushManager<=Proc{1902:com.android.phone/1001}
02-09 17:15:20.887217 1164 13478 I ActivityManager: prcp IMPB 65781: com.sohu.inputmethod.sogou (pid 11697) service
02-09 17:15:20.887217 1164 13478 I ActivityManager: com.sohu.inputmethod.sogou/.SogouIME<=Proc{1164:system/1000}
02-09 17:15:20.887217 1164 13478 I ActivityManager: prcp IMPB 13053: com.android.webview:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:0 (pid 12509) service
02-09 17:15:20.887217 1164 13478 I ActivityManager: com.sohu.inputmethod.sogou/org.chromium.content.app.SandboxedProcessService0:0<=Proc{11697:com.sohu.inputmethod.sogou/u0a151}
02-09 17:15:20.887217 1164 13478 I ActivityManager: svc SVC 22194: com.sohu.inputmethod.sogou:push_service (pid 12588) started-services
02-09 17:15:20.887217 1164 13478 I ActivityManager: prev LAST 19057: com.android.packageinstaller (pid 11380) previous
02-09 17:15:20.887217 1164 13478 I ActivityManager: 2227718: TOTALRecently, I often encounter logcat Print in Low on memory, Here we will analyze the source code .
It is roughly divided into the following parts :
- log What is the basis of the information in ?
- In addition to this information, what are the key points ?
- The log How to trigger printing ?
1. reportMemUsage
log The characters in are easy to find from the source code , And information processing is all in reportMemUsage in , Because there are many function processing logics , Here the analysis is carried out in sections .
Code path :frameworks/base/services/core/java/com/android/server/am/AMS.java
void reportMemUsage(ArrayList<ProcessMemInfo> memInfos) {
Parameters are discussed below , Here we think it is the result of all processes ProcessMemInfo.
step1. Arrangement ProcessMemInfo
final SparseArray<ProcessMemInfo> infoMap = new SparseArray<>(memInfos.size());
for (int i=0, N=memInfos.size(); i<N; i++) {
ProcessMemInfo mi = memInfos.get(i);
infoMap.put(mi.pid, mi);
}take ProcessMemInfo Save to new SparseArray in .
step2. to update CPU state
Then, through the function updateCpuStatsNow() Update at this point CPU state , The code of the function is not posted , You can check the source code if you are interested , Also in AMS.java in .
The main attention is to member variables mProcessCpuTracker, adopt update Function update data :
void updateCpuStatsNow() {
synchronized (mProcessCpuTracker) {
...
mProcessCpuTracker.update();---->upodate()
frameworks/base/core/java/com/android/internal/os/ProcessCpuTracker.java
public void update() {
...
if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
null, sysCpu, null)) {
...
}
...
try {
mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
} finally {
StrictMode.setThreadPolicy(savedPolicy);
}
...
final float[] loadAverages = mLoadAverageData;
if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
null, null, loadAverages)) {
...
}
...
}- Read /proc/stat Node related information , for example user time、system time、io wait time、irq time、idle time etc. ;
- collectStats collect /proc All process information under the directory ;
- Read /proc/loadavg Node information ,dumpsys cpuinfo perhaps ANR It will be printed when ;
step3. Acquisition process PSS
for (int i = 0; i < statsCount; i++) {
ProcessCpuTracker.Stats st = stats.get(i);
long pss = Debug.getPss(st.pid, swaptrackTmp, memtrackTmp);
if (pss > 0) {
if (infoMap.indexOfKey(st.pid) < 0) {
ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
ProcessList.NATIVE_ADJ, -1, "native", null);
mi.pss = pss;
mi.swapPss = swaptrackTmp[1];
mi.memtrack = memtrackTmp[0];
memInfos.add(mi);
}
}
}
long totalPss = 0;
long totalSwapPss = 0;
long totalMemtrack = 0;
for (int i=0, N=memInfos.size(); i<N; i++) {
ProcessMemInfo mi = memInfos.get(i);
if (mi.pss == 0) {
mi.pss = Debug.getPss(mi.pid, swaptrackTmp, memtrackTmp);
mi.swapPss = swaptrackTmp[1];
mi.memtrack = memtrackTmp[0];
}
totalPss += mi.pss;
totalSwapPss += mi.swapPss;
totalMemtrack += mi.memtrack;
}step4. Yes ProcessMemInfo according to oom adj Sort
Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
@Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
if (lhs.oomAdj != rhs.oomAdj) {
return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
}
if (lhs.pss != rhs.pss) {
return lhs.pss < rhs.pss ? 1 : -1;
}
return 0;
}
});If oom adj There is a small to large order , If oom adj identical , According to pss From big to small .
step5. to update tag builder
stay reportMemUsage There are several important in this function StringBuilder object , These objects contain late logcat and DropBox Information required for document printing .
there tag builder, It's for later drop box Prepare information .
for (int i=0, N=memInfos.size(); i<N; i++) {
ProcessMemInfo mi = memInfos.get(i);
if (mi.oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
cachedPss += mi.pss;
}
if (mi.oomAdj != ProcessList.NATIVE_ADJ
&& (mi.oomAdj < ProcessList.SERVICE_ADJ
|| mi.oomAdj == ProcessList.HOME_APP_ADJ
|| mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
if (lastOomAdj != mi.oomAdj) {
lastOomAdj = mi.oomAdj;
if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
tag.append(" / ");
}
if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
if (firstLine) {
stack.append(":");
firstLine = false;
}
stack.append("\n\t at ");
} else {
stack.append("$");
}
} else {
tag.append(" ");
stack.append("$");
}
if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
appendMemBucket(tag, mi.pss, mi.name, false);
}
appendMemBucket(stack, mi.pss, mi.name, true);
if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
&& ((i+1) >= N || memInfos.get(i+1).oomAdj != lastOomAdj)) {
stack.append("(");
for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
stack.append(DUMP_MEM_OOM_LABEL[k]);
stack.append(":");
stack.append(DUMP_MEM_OOM_ADJ[k]);
}
}
stack.append(")");
}
}step6. to update full Native builder and short Native builder、java builder
appendMemInfo(fullNativeBuilder, mi);
if (mi.oomAdj == ProcessList.NATIVE_ADJ) {
// The short form only has native processes that are >= 512K.
if (mi.pss >= 512) {
appendMemInfo(shortNativeBuilder, mi);
} else {
extraNativeRam += mi.pss;
extraNativeMemtrack += mi.memtrack;
}
} else {
// Short form has all other details, but if we have collected RAM
// from smaller native processes let's dump a summary of that.
if (extraNativeRam > 0) {
appendBasicMemEntry(shortNativeBuilder, ProcessList.NATIVE_ADJ,
-1, extraNativeRam, extraNativeMemtrack, "(Other native)");
shortNativeBuilder.append('\n');
extraNativeRam = 0;
}
appendMemInfo(fullJavaBuilder, mi);
}- In memory 512KB Above native Process information will be stored in shortNativeBuilder in ;
- In memory 512KB Below is the sum of Statistics , And finally Other native The form is spliced in shortNativeBuilder;
- Java Process information is placed in fullJavaBuilder in ;
fullJavaBuilder.append(" ");
ProcessList.appendRamKb(fullJavaBuilder, totalPss);
fullJavaBuilder.append(": TOTAL");
if (totalMemtrack > 0) {
fullJavaBuilder.append(" (");
fullJavaBuilder.append(stringifyKBSize(totalMemtrack));
fullJavaBuilder.append(" memtrack)");
} else {
}
fullJavaBuilder.append("\n");stay fullJavaBuilder Finally, add the last total pss. There could be total memtrack.
step7. Read /proc/meminfo Information
MemInfoReader memInfo = new MemInfoReader();
memInfo.readMemInfo();
final long[] infos = memInfo.getRawInfo();Read meminfo Store in MemInfoReader Member variable in mInfos in , Through interface getRawInfo obtain ;
step8. according to meminfo to update MemInfoBuilder
Too much code , No more , Take a look log:
02-09 17:15:20.887254 1164 13478 I ActivityManager: MemInfo: 192,372K slab, 13,844K shmem, 70,432K vm alloc, 44,800K page tables 30,704K kernel stack
02-09 17:15:20.887254 1164 13478 I ActivityManager: 880K buffers, 349,444K cached, 286,888K mapped, 1,012,108K free
02-09 17:15:20.887254 1164 13478 I ActivityManager: ZRAM: 166,244K RAM, 1,572,860K swap total, 1,047,972K swap free
02-09 17:15:20.887254 1164 13478 I ActivityManager: Free RAM: 1,126,524K
02-09 17:15:20.887254 1164 13478 I ActivityManager: ION: 149,764K
02-09 17:15:20.887254 1164 13478 I ActivityManager: Used RAM: 2,615,922K
02-09 17:15:20.887254 1164 13478 I ActivityManager: Lost RAM: -671,218Kstep9. logcat Print
Slog.i(TAG, "Low on memory:");
Slog.i(TAG, shortNativeBuilder.toString());
Slog.i(TAG, fullJavaBuilder.toString());
Slog.i(TAG, memInfoBuilder.toString());Here is the logcat See the print , Three main aspects :
- shortNativeBuilder Count all items greater than 512KB Of native The process of , Others are less than 512KB Of native Will be with other appear ;
- fullJavaBuilder Statistics of all java Information about the process ;
- memInfoBuilder Count the current process /proc/meminfo;
Be careful logcat Medium
02-09 17:15:20.887217 1164 13478 I ActivityManager: pers PER 83753: com.android.systemui (pid 1520) fixed
02-09 17:15:20.887217 1164 13478 I ActivityManager: pers PER 51579: com.android.phone (pid 1902) fixedBe careful TAG The last two columns ,pers、PER They correspond to each other oom adj and proc state.
Let's start with oom adj Corresponding string:
- cch ---- CACHED_APP_MIN_ADJ
- svcb ---- SERVICE_B_ADJ
- prev ---- PREVIOUS_APP_ADJ
- home ---- HOME_APP_ADJ
- svc ---- SERVICE_ADJ
- hvy ---- HEAVY_WEIGHT_APP_ADJ
- bkup ---- BACKUP_APP_ADJ
- prcl ---- PERCEPTIBLE_LOW_APP_ADJ
- prcp ---- PERCEPTIBLE_APP_ADJ
- vis ---- VISIBLE_APP_ADJ
- fg ---- FOREGROUND_APP_ADJ
- psvc ---- PERSISTENT_SERVICE_ADJ
- pers ---- PERSISTENT_PROC_ADJ
- sys ---- SYSTEM_ADJ
- ntv ---- NATIVE_ADJ
And then look at proc state Corresponding string:
- PER ---- PROCESS_STATE_PERSISTENT
- PERU ---- PROCESS_STATE_PERSISTENT_UI
- TOP ---- PROCESS_STATE_TOP
- BTOP ---- PROCESS_STATE_BOUND_TOP
- FGS ---- PROCESS_STATE_FOREGROUND_SERVICE
- BFGS ---- PROCESS_STATE_BOUND_FOREGROUND_SERVICE
- IMPF ---- PROCESS_STATE_IMPORTANT_FOREGROUND
- IMPB ---- PROCESS_STATE_IMPORTANT_BACKGROUND
- TRNB ---- PROCESS_STATE_TRANSIENT_BACKGROUND
- BKUP ---- PROCESS_STATE_BACKUP
- SVC ---- PROCESS_STATE_SERVICE
- RCVR ---- PROCESS_STATE_RECEIVER
- TPSL ---- PROCESS_STATE_TOP_SLEEPING
- HVY ---- PROCESS_STATE_HEAVY_WEIGHT
- HOME ---- PROCESS_STATE_HOME
- LAST ---- PROCESS_STATE_LAST_ACTIVITY
- CAC ---- PROCESS_STATE_CACHED_ACTIVITY
- CACC ---- PROCESS_STATE_CACHED_ACTIVITY_CLIENT
- CRE ---- PROCESS_STATE_CACHED_RECENT
- CEM ---- PROCESS_STATE_CACHED_EMPTY
- NONE ---- PROCESS_STATE_CACHED_EMPTY
- other ---- ??
step10. Arrangement dropBuilder
Pass above stack builder、fullNativeBuilder、fullJavaBuilder、memInfoBuilder Arrangement dropBuilder Used to output drop box.
2. Trigger reportMemUsage
Next, analyze the reasons for triggering these printing .
2.1 reportMemUsage From message REPORT_MEM_USAGE_MSG
From the code context , Trigger reportMemUsage() There's only one place , Namely MainHandler Medium REPORT_MEM_USAGE_MSG news :
case REPORT_MEM_USAGE_MSG: {
final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
Thread thread = new Thread() {
@Override public void run() {
reportMemUsage(memInfos);
}
};
thread.start();
break;
}This message comes with a parameter , Namely reportMemUsage() Parameters in function , in addition , This function is in a Separate threads In the implementation of .
2.2 Message from doLowMemReportIfNeededLocked issue
in addition , There is only one place to send this message , Namely doLowMemReportIfNeededLocked():
final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
// If there are no longer any background processes running,
// and the app that died was not running instrumentation,
// then tell everyone we are now low on memory.
if (!mProcessList.haveBackgroundProcessLocked()) {
boolean doReport = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
if (doReport) {
long now = SystemClock.uptimeMillis();
if (now < (mLastMemUsageReportTime+5*60*1000)) {
doReport = false;
} else {
mLastMemUsageReportTime = now;
}
}
final ArrayList<ProcessMemInfo> memInfos
= doReport ? new ArrayList<ProcessMemInfo>(mProcessList.getLruSizeLocked())
: null;
EventLogTags.writeAmLowMemory(mProcessList.getLruSizeLocked());
long now = SystemClock.uptimeMillis();
for (int i = mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord rec = mProcessList.mLruProcesses.get(i);
if (rec == dyingProc || rec.thread == null) {
continue;
}
if (doReport) {
memInfos.add(new ProcessMemInfo(rec.processName, rec.pid, rec.setAdj,
rec.setProcState, rec.adjType, rec.makeAdjReason()));
}
if ((rec.lastLowMemory+mConstants.GC_MIN_INTERVAL) <= now) {
// The low memory report is overriding any current
// state for a GC request. Make sure to do
// heavy/important/visible/foreground processes first.
if (rec.setAdj <= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
rec.lastRequestedGc = 0;
} else {
rec.lastRequestedGc = rec.lastLowMemory;
}
rec.reportLowMemory = true;
rec.lastLowMemory = now;
mProcessesToGc.remove(rec);
addProcessToGcListLocked(rec);
}
}
if (doReport) {
Message msg = mHandler.obtainMessage(REPORT_MEM_USAGE_MSG, memInfos);
mHandler.sendMessage(msg);
}
scheduleAppGcsLocked();
}
}The details of this function need attention :
- Need to print mem usage, need ro.debuggable Yes, it is 1 Of , The default value is 0. That's it Printing will only appear in user debug or engine edition ;
- Printed on 5 It will only appear once in minutes ;
- The printed memory information will only be the current or process ;
2.3 doLowMemReportIfNeededLocked Trigger
Trigger source of function :
- killAllBackgroundProcesses() The function is AMS External interface function of , It is used for users to actively call
- appDiedLocked() This paper mainly analyzes the trigger process of this function
2.4 appDiedLocked
private final class AppDeathRecipient implements IBinder.DeathRecipient {
final ProcessRecord mApp;
final int mPid;
final IApplicationThread mAppThread;
AppDeathRecipient(ProcessRecord app, int pid,
IApplicationThread thread) {
...
}
@Override
public void binderDied() {
...
synchronized(ActivityManagerService.this) {
appDiedLocked(mApp, mPid, mAppThread, true, null);
}
}
}If you want to see appDiedLocked This method , The first thing to know is that ActivityThread.main() in , Starting from here, the process will be bound from this method after creation AMS, stay AMS By calling AMS.attachApplicationLocked() This method starts binding , In this method, there will be right ApplicationThreadProxy Binding notification :
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
final String processName = app.processName;
try {
AppDeathRecipient adr = new AppDeathRecipient(
app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
} catch (RemoteException e) {
...
}
...among IApplicationThread thread Is in ActivityThread The process created in belongs to the newly created process ( For example, new app The process of ).client Namely ApplicationThreadProxy object , The object is AMS in ,AMS Is in system_server in . So when we binder server When you die (app Process death ) We system_server The process will be notified , Then do something about it .

边栏推荐
- Leetcode 42. rainwater connection
- 苏黎世联邦理工学院 | 具有可变形注意Transformer 的基于参考的图像超分辨率(ECCV2022))
- Initialization examples of several modes of mma8452q
- [graduation design] oscilloscope design and Implementation Based on STM32 - single chip microcomputer Internet of things
- Solution to using json.tojsonstring to display question marks in Chinese in Servlet
- Which big model is better? Openbmb releases bmlist to give you the answer!
- 机器学习实战-决策树-22
- Siemens docking Leuze BPS_ 304i notes
- Hc-05 Bluetooth module debugging slave mode and master mode experience
- 【嵌入式C基础】第8篇:C语言数组讲解
猜你喜欢

Huawei cloud Gao Hongxia: CBC microservice code Reconstruction & independent release practice

【嵌入式C基础】第4篇:运算符的使用

scala 转换、过滤、分组、排序

Li FuPan: application practice of kata safety container in ant group

Change the document type in endnode and import it in word

机器学习实战-逻辑回归-19
![[embedded explanation] key scanning based on finite state machine and stm32](/img/ce/cc3f959a4e4f5b22e2c711ea887ad7.png)
[embedded explanation] key scanning based on finite state machine and stm32

Jetpack Compose 完全脱离 View 系统了吗?

BiliBili Yang Zhou: above efficiency, efficient delivery

Introduction to border border attribute
随机推荐
DART 三维辐射传输模型申请及下载
机器学习基础-主成分分析PCA-16
QT signal and slot mechanism (detailed)
Hc-05 Bluetooth module debugging slave mode and master mode experience
Li FuPan: application practice of kata safety container in ant group
Brief introduction to JS operator
[graduation design] heart rate detection system based on single chip microcomputer - STM32 embedded Internet of things
Force buckle 315 calculates the number of elements smaller than the current element on the right
The input string contains an array of numbers and non characters, such as a123x456. Take the consecutive numbers as an integer, store them in an array in turn, such as 123 in a[0], 456 in a[1], and ou
机器学习实战-决策树-22
LeetCode 移除元素&移动零
[Bi design teaching] STM32 and FreeRTOS realize low power consumption
What if the win11 folder cannot be opened
CCF201912-2 回收站选址
Communication example between upper computer and Mitsubishi fn2x
Science 重磅:AI设计蛋白质再获突破,可设计特定功能性蛋白质
Redefinition problem of defining int i variable in C for loop
[basic teaching of Bi design] detailed explanation of OLED screen use - single chip microcomputer Internet of things
Databinding+LiveData轻松实现无重启换肤
第九章 REST 服务安全