深入探索Android卡顿优化(上)

此外,如果你需要分析Native 函数的调用,请使用Android 5.0 新增的[Simpleperf](()性能分析工具,它利用了 CPU 的性能监控单元(PMU)提供的硬件 perf 事件。使用 Simpleperf 可以看到所有的 Native 代码的耗时,对一些 Android 系统库的调用,在分析问题时有比较大的帮助,例如分析加载 dex、verify class 的耗时等等。此外,在 Android Studio 3.2 中的 Profiler 也直接支持了 Simpleper(SampleNative性能分析工具 (API Level 26+)),这更加方便了native代码的调试。

3、StrictMode

StrictMode是Android 2.3引入的一个工具类,它被称为严苛模式,是Android提供的一种运行时检测机制,可以用来帮助开发人员用来检测代码中一些不规范的问题。对于我们的项目当中,可能会成千上万行代码,如果我们用肉眼Review,这样不仅效率非常低效,而且比较容易出问题。使用StrictMode之后,系统会自动检测出来在主线程中的一些异常情况,并按照我们的配置给出相应的反应

StrictMode这个工具是非常强大的,但是我们可能因为对它不熟悉而忽略掉它。StrictMode主要用来检测两大问题:

1、线程策略

线程策略的检测内容,是一些自定义的耗时调用、磁盘读取操作以及网络请求等

2、虚拟机策略

虚拟机策略的检测内容如下:

  • Activity泄漏
  • Sqlite对象泄漏
  • 检测实例数量
StrictMode实战

如果要在应用中使用StrictMode,只需要在Applicaitoin的onCreate方法中对StrictMode进行统一配置,代码如下所示:

private void initStrictMode() { Android开源项目《ali1024.coding.net/public/P7/Android/git》
// 1、设置Debug标志位,仅仅在线下环境才使用StrictMode
if (DEV_MODE) {
// 2、设置线程策略
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectCustomSlowCalls() //API等级11,使用StrictMode.noteSlowCode
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog() //在Logcat 中打印违规异常信息
// .penaltyDialog() //也可以直接跳出警报dialog
// .penaltyDeath() //或者直接崩溃
.build());
// 3、设置虚拟机策略
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
// 给NewsItem对象的实例数量限制为1
.setClassInstanceLimit(NewsItem.class, 1)
.detectLeakedClosableObjects() //API等级11
.penaltyLog()
.build());
}
}

最后,在日志输出栏中注意使用“StrictMode”关键字过滤出对应的log即可。

4、Profilo

Profilo是一个用于收集应用程序生产版本的性能跟踪的Android库。

对于Profilo来说,它集成了atrace功能,ftrace 所有的性能埋点数据都会通过 trace_marker 文件写入到内核缓冲区,Profilo 使用了 PLT Hook 拦截了写入操作,以选择部分关心的事件去做特定的分析。这样所有的 systrace 的探针我们都可以拿到,例如四大组件生命周期、锁等待时间、类校验、GC 时间等等。不过大部分的 atrace 事件都比较笼统,从事件“B|pid|activityStart”,我们无法明确知道该事件具体是由哪个 Activity 来创建的。

此外,使用Profilo还能够快速获取Java堆栈。由于获取堆栈需要暂停主线程的运行,所以profilo通过间隔发送 SIGPROF 信号这样一种类似 Native 崩溃捕捉的方式去快速获取 Java 堆栈

Profilo能够低耗时地快速获取Java堆栈的具体实现原理为当Signal Handler 捕获到信号后,它就会获取到当前正在执行的 Thread,通过 Thread 对象就可以拿到当前线程的 ManagedStack,ManagedStack 是一个单链表,它保存了当前的 ShadowFrame 或者 QuickFrame 栈指针,先依次遍历 ManagedStack 链表,然后遍历其内部的 ShadowFrame 或者 QuickFrame 还原一个可读的调用栈,从而 unwind 出当前的 Java 堆栈。关于ManagedStack与ShadowFrame、QuickFrame三者的关系如下图所示:

image

Profilo通过这种方式,就可以实现线程同步运行的同时,我们还可以去帮它做检查,并且耗时基本可以忽略不计。但是目前 Profilo 快速获取堆栈的功能不支持 Android 8.0 和 Android 9.0,并且它内部使用了Hook等大量的黑科技手段,鉴于稳定性问题,建议采取抽样部分用户的方式来开启该功能。

[Profilo项目地址](()

前面我们说过,Profilo最终也使用了ftrace,而Systrace主要也是根据Linux的ftrace机制来实现的,而ftrace的作用是帮助我们了解 Linux 内核的运行时行为,以便进行故障调试或性能分析。ftrace的整体架构如下所示:

image

由上图可知,Ftrace 有两大组成部分,一个是 framework,另外就是一系列的 tracer 。每个 tracer 用于完成不同的功能,并且它们统一由 framework 管理。 ftrace 的 trace 信息保存在 ring buffer 中,由 framework 负责管理。 Framework 利用 debugfs 系统在 /debugfs 下建立 tracing 目录,并提供了一系列的控制文件。

下面,我这里给出使用 PLTHook 技术来获取 Atrace 日志的一个项目。

1、使用profilo的PLTHook来hook libc.so的 write 与 __write_chk 方法

[使用 PLTHook 技术来获取 Atrace 的日志-项目地址](()

运行项目后,我们点击按钮开启Atrace日志,然后就可以在Logcat中看到如下的native层日志信息:

2020-02-05 10:58:00.873 13052-13052/com.dodola.atrace I/HOOOOOOOOK: =install systrace hoook====
2020-02-05 10:58:00.879 13052-13052/com.dodola.atrace I/HOOOOOOOOK: ========= B|13052|inflate
2020-02-05 10:58:00.880 13052-13052/com.dodola.atrace I/HOOOOOOOOK: ========= B|13052|LinearLayout
2020-02-05 10:58:00.881 13052-13052/com.dodola.atrace I/HOOOOOOOOK: ========= E
2020-02-05 10:58:00.882 13052-13052/com.dodola.atrace I/HOOOOOOOOK: ========= B|13052|TextView
2020-02-05 10:58:00.884 13052-13052/com.dodola.atrace I/HOOOOOOOOK: ========= E
2020-02-05 10:58:00.885 13052-13052/com.dodola.atrace I/HOOOOOOOOK: ========= E
2020-02-05 10:58:00.888 13052-13075/com.dodola.atrace I/HOOOOOOOOK: ========= B|13052|notifyFramePending
2020-02-05 10:58:00.888 13052-13075/com.dodola.atrace I/HOOOOOOOOK: ========= E
2020-02-05 10:58:00.889 13052-13052/com.dodola.atrace I/HOOOOOOOOK: ========= B|13052|Choreographer#doFrame
2020-02-05 10:58:00.889 13052-13052/com.dodola.atrace I/HOOOOOOOOK: ========= B|13052|input
2020-02-05 10:58:00.889 13052-13052/com.dodola.atrace I/HOOOOOOOOK: ========= E
2020-02-05 10:58:00.889 13052-13052/com.dodola.atrace I/HOOOOOOOOK: ========= B|13052|traversal
2020-02-05 10:58:00.889 13052-13052

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值