上一篇文章已经分析了画面帧率的监控原理,现在来分析内存使用的原理和技巧。
按惯例,先了解一下计算机内存方面的基本知识。作为计算机三大件中的一个角色(CPU、内存、硬盘),内存就像一个缓冲区,让CPU更快地从内存中获得数据,让硬盘更方便地将数据写入到内存中(硬盘的IO操作相对耗时)。但这个缓冲区不是无限量的大,有一定的空间限制,如果写入的数据太多,会将缓冲区填满,那程序就会崩溃(OOM)。即使不填满,剩余不多的时候也会影响程序的正常运行。
问题一:我通过什么方式来获得系统运行时的内存数据?
我现在知道内存的作用了,但我不知道从哪里、通过什么方式获得这些数据。这里用到android.os.Debug这个对象。下面是头部介绍。
/**
* Provides various debugging methods for Android applications, including
* tracing and allocation counts.
* <p><strong>Logging Trace Files</strong></p>
* <p>Debug can create log files that give details about an application, such as
* a call stack and start/stop times for any running methods. See <a
* href="{@docRoot}studio/profile/traceview.html">Inspect Trace Logs with
* Traceview</a> for information about reading trace files. To start logging
* trace files, call one of the startMethodTracing() methods. To stop tracing,
* call {@link #stopMethodTracing()}.
*/
可以通过这个对象获得程序运行的各种信息。
另外在ActivityManager中也有一个方法,可以获得指定进程的内存使用情况,返回的也是Debug对象。
/**
* Return information about the memory usage of one or more processes.
*
* <p><b>Note: this method is only intended for debugging or building
* a user-facing process management UI.</b></p>
*
* @param pids The pids of the processes whose memory usage is to be
* retrieved.
* @return Returns an array of memory information, one for each
* requested pid.
*/
public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids) {
try {
return getService().getProcessMemoryInfo(pids);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
关于系统的内存信息数据,可以在【/proc/meminfo】这个文件中获取,这个文件会实时地更新整个系统地内存数据并写入到该文件中。所以可以直接读这个文件的内容来获得内存信息。
问题二:你说的我都看得懂,但我还是不知道怎么写,你直接写出来让我copy吧,我太难了
内存信息采样没必要做到很频繁,毕竟大部分都不是高频运算程序,即使是游戏,也只是实时对战的时候才是高频运算,摸摸自己的手机就知道。所以可以限定1个小时采样一次。
/**
* 获取当前内存信息,耗时操作,再子线程操作
* @return
*/
private MemoryInfo getMemoryInfo() {
int pid = android.os.Process.myPid();
Context context = Manager.getContext();
ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(new int[]{pid});
long currentUsedMem = memoryInfoArray[0].getTotalPrivateDirty();
long totalMem = getTotalMem();
if (Manager.isDebug()) {
ApmLogX.d(APM_TAG, SUB_TAG,
"当前应用使用内存:" + Formatter.formatFileSize(context, currentUsedMem * 1024) + "的内存" +
" 系统总内存:" + Formatter.formatFileSize(context, totalMem * 1024));
}
Debug.MemoryInfo info = new Debug.MemoryInfo();
Debug.getMemoryInfo(info);
if (Manager.isDebug()) {
ApmLogX.d(APM_TAG, SUB_TAG,
"currentProcess:" + ProcessUtils.getCurrentProcessName()
+ " dalvikPss:" + info.dalvikPss
+ " nativePss:" + info.nativePss
+ " otherPass:" + info.otherPss
+ " totalPss:" + info.getTotalPss());
}
return new MemoryInfo(ProcessUtils.getCurrentProcessName(), currentUsedMem, totalMem, info.dalvikPss, info.nativePss, info.otherPss, info.getTotalPss());
}
private long getTotalMem() {
String meminfoFile = "/proc/meminfo";
long initial_memory = 0;
try {
FileReader localFileReader = new FileReader(meminfoFile);
BufferedReader bufferedReader = new BufferedReader(localFileReader, 8192);
String content = bufferedReader.readLine(); // 只读第一行,获得系统总内存信息
String[] arrayOfString = content.split("\\s+");
for (String text : arrayOfString) {
Log.i(SUB_TAG, "value:" + text);
}
initial_memory = Long.parseLong(arrayOfString[1]);
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
return initial_memory;
}
这里又延伸出一个细节,PSS是什么?
PSS学术名称叫做“比例集大小(proportional set size)”
是一个系统给出来地分数,用于判断是否需要将这个运行中的程序杀死,如果总得分非常高,那系统很可能会立刻将这个程序kill掉。
多高才算高?这个不知道,但系统会做综合判断。好了,整个运行时的内存信息已经获取完毕,Debug对象内部还有很多信息可以获取,想拿什么就去拿什么吧...
网友评论