美文网首页
云米客户端APM性能监控组件分析(四)

云米客户端APM性能监控组件分析(四)

作者: 捉影T_T900 | 来源:发表于2020-04-09 15:55 被阅读0次

上一篇文章已经分析了画面帧率的监控原理,现在来分析内存使用的原理和技巧。

按惯例,先了解一下计算机内存方面的基本知识。作为计算机三大件中的一个角色(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对象内部还有很多信息可以获取,想拿什么就去拿什么吧...

未完待续......

相关文章

网友评论

      本文标题:云米客户端APM性能监控组件分析(四)

      本文链接:https://www.haomeiwen.com/subject/sfluyctx.html