Android性能分析工具

新版本Profiler

Android Studio Koala

image.png
  • 褐色图标: 设备性能实时展示
  • 红色图标: 设备整体性能抓取
  • 橙色图标: CPU性能相关
  • 绿色图标: 内存性能相关

View Live Telemetry

image.png
  • 优点:
    直观的展示当前设备CPU、内存、线程等的状态
  • 缺点:
    没有做数据统计,不好做数据分析

Caputure System Activities

  • User/Lifecycle

用户的交互,页面元素展示

image.png
  • Janky Frame

卡顿帧、卡顿发生的时间、卡顿时的堆栈

image.png
  • Threads
    抓取数据阶段本设备运行的线程信息
    包括线程运行时间、执行堆栈的概览

只能看到概览,详细分析较为困难

  • CPU cores
    CPU运行频率、单位时间执行的线程信息
image.png
在排查问题时如何判定CPU是否负载过重?
CPU大小核任务的分配
  1. 大核(Big Core):主要用于高性能任务,如游戏、视频渲染等。大核的运行速度更快,频率更高,性能更强,但同时耗电量也更大。通常,当设备需要处理密集计算任务或对性能有较高需求时,系统会将任务分配到大核上,以保证流畅度和响应速度。

  2. 小核(LITTLE Core):主要用于低功耗任务,如待机、后台处理等。小核的运行频率较低,性能相对弱,但非常省电。通常在执行低强度的任务时,系统会将任务分配给小核,从而延长设备的电池寿命。

RSS

进程实际RSS分配

image.png

FInd CPU HotSpots

  1. Java/Kotlin Method Recording(方法记录模式)
    工作原理:这种模式会在应用程序的每个 Java 或 Kotlin 方法开始和结束时插入钩子,以便捕获每个方法的精确调用次数和执行时长。
    数据精度:由于这种模式会记录每个方法的进入和退出时间,因此可以精确地计算方法的执行时间和调用关系,生成详尽的调用图谱。它适合用来分析方法的具体调用频率和精确的时间消耗。
    开销:因为要跟踪每个方法的开始和结束,方法记录模式会增加额外的运行时开销(即分析过程本身可能影响应用的运行性能)。
    适用场景:适合需要精确分析方法调用频率和耗时的场景,尤其是需要知道具体的 CPU 使用位置时(如热点方法或高频方法)。
  2. CallStack Sample(调用栈采样模式)
    工作原理:调用栈采样模式采用的是采样机制,在固定的时间间隔(比如每隔几毫秒)对应用程序的调用栈进行快照,记录当前正在执行的方法。这种方式不会记录方法的进入和退出时间,而是定期采集某个时间点的调用栈信息。
    数据精度:由于是定期采样,数据精度相对较低,特别是在快速调用的方法上会出现遗漏。采样方法只能提供粗略的 CPU 使用率和热点信息。
    开销:采样模式的开销相对较低,因为它不需要跟踪每个方法的开始和结束,只是在固定间隔拍下快照,因此对应用性能的影响较小。
    适用场景:适合对性能要求较高的应用进行整体性能分析和热点方法定位,不适合需要精确计时的分析场景。
    为什么两者的 CPU 使用率不一样?
    数据捕获方式不同:方法记录模式记录的是每个方法的精确开始和结束时间,而调用栈采样模式只是定期捕获当前执行的方法,因此在方法调用频率和执行时间的捕获上存在精度差异。方法记录模式提供更精确的调用信息,但由于采样时间粒度的原因,采样模式可能会漏掉一些短时或快速调用的方法。

采样时间间隔的影响:在调用栈采样模式中,采样间隔会影响捕获的数据量。如果采样间隔较大,某些执行较短的方法可能在采样间隔内未被捕获,从而影响 CPU 使用率的计算。方法记录模式不受采样间隔的影响,因此它的 CPU 使用率计算更加准确。

采样模式偏向粗略分析:调用栈采样模式的设计初衷是提供一个低开销、适用于长时间监控的性能分析方式,而方法记录模式则偏向短时间、精确的分析。这导致了在长时间分析中,采样模式的结果会更贴近真实情况,而在短时间或精确分析时,方法记录模式则提供更精确的结果。

如何选择
如果需要精确的 CPU 使用分析,并且可以接受一定的性能开销,则选择 Java/Kotlin Method Recording。
如果需要对应用程序整体 CPU 使用情况的粗略概览,并且希望开销较小,则选择 CallStack Sample。

获取CPU工作情况

  • Wall Clock Time
    线程存在的时间
  • Thread Time
    线程真正工作的时间

查找性能瓶颈,主要是查看线程真正的工作时间与总时间的比,即CPU使用率

排序:

  • Top Down
    按照时间降序排列
  • Bottom Up
    按照时间升序排列
  • Flame Chart
    火焰图
    Flame Chart 的结构
    火焰图通常是由横向矩形条组成的,每个矩形条代表一个函数调用:

X 轴:表示时间轴,条的宽度表示该函数执行的时长。
Y 轴:表示调用栈深度,越靠上表示函数调用的嵌套越深。
颜色:通常不代表具体含义,但有时不同的颜色可以用于区分不同的模块、线程或函数类型。
工作原理
火焰图的生成通常基于采样堆栈跟踪或基于事件的分析:

采样堆栈跟踪:在程序运行时定期采样调用栈,记录每个时刻的调用情况。然后,将这些调用栈信息聚合并可视化。
事件跟踪:当函数调用开始和结束时记录事件,通过记录的时间点生成函数调用的时间分布图。
如何解读 Flame Chart
宽度:矩形条越宽,表示该函数执行时间越长,是性能瓶颈的潜在候选。
高度:代表了函数的调用层级。深层嵌套通常表明复杂的调用关系,可能导致性能问题。
上层函数:火焰图的上层函数调用的是下层函数。如果某个高频函数的子调用占用了大量时间,则可能需要优化该函数的逻辑。

根据CPU占用率,有针对性的优化代码
  • Sample
new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    //getRealTemp("");
                    checkStringMatch("aaa-0-ccc");
                    try {
                        synchronized (lock) {
                            lock.wait(100);
                        }
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }).start();

private void checkStringMatch(String testStr) {
        long startTime = System.currentTimeMillis();
        int count = 0;
        for (int i = 0; i < 1000; i++) {
            /*String regex = "aaa-\\d-ccc";
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(testStr);
            if (matcher.matches()) {
                count++;
            }*/
            if (testStr.startsWith("aaa") && testStr.endsWith("ccc")) {
                count++;
            }
        }
        long costTime = System.currentTimeMillis() - startTime;
        Log.d("zyl", "costTime = " + costTime);
    }

Find CPU Hotspots(Java/Kotlin)

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容