01 | 崩溃优化(上):关于“崩溃”那些事儿

  • anr检测:
  1. FileObserver 监听 /data/anr/traces.txt 的变化(5.0以后没有权限使用)
  2. ANR-WatchDog
  3. SafeLooper
  4. BlockCanary
  • native崩溃日志捕获:Breakpad

03 | 内存优化(上)

VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)

获取系统配置:/system/build.prop,如:

dalvik.vm.heapgrowthlimit=256m
dalvik.vm.heapsize=512m
dalvik.vm.stack-trace-file=/data/anr/traces.txt

自身内存占用监控:

Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

查看整体内存分配:

adb shell dumpsys meminfo <package_name|pid> [-d]
adb shell dumpsys activity <package_name|pid> [-d]

04 | 内存优化(下)

GC 监控

long allocCount = Debug.getGlobalAllocCount();
long allocSize = Debug.getGlobalAllocSize();
long gcCount = Debug.getGlobalGcInvocationCount();

05 | 卡顿优化(上):你要掌握的卡顿分析方法:

获取 CPU 核心数

cat /sys/devices/system/cpu/possible
	cat proc/cpuinfo:
	cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq:// 获取某个 CPU 的频率
	cat proc/stat:// 获取整个系统cpu使用情况
	cat /proc/[pid]/stat:// 获取单个进程cpu使用情况
	top:查看所有进程cpu占比
	vmstat:查看操作系统的虚拟内存和cpu活动
	uptime:检查 CPU 在 1 分钟、5 分钟和 15 分钟内的平均负载
	proc/self/stat:
	utime:       用户时间,反应用户代码执行的耗时  
	stime:       系统时间,反应系统调用执行的耗时
	majorFaults:需要硬盘拷贝的缺页次数
	minorFaults:无需硬盘拷贝的缺页次数
	proc/self/sched:
	nr_voluntary_switches:     主动上下文切换次数,因为线程无法获取所需资源导致上下文切换,最普遍的是 IO。    
	nr_involuntary_switches:   被动上下文切换次数,线程被系统强制调度导致上下文切换,例如大量线程在抢占 CPU。
	se.statistics.iowait_count:IO 等待的次数
	se.statistics.iowait_sum:  IO 等待的时间

Android 卡顿排查工具

  1. Traceview:将函数运行的耗时和调用关系写入 trace 文件中(debug和releaes模式下均可用)
  2. Nanoscope:
  3. systrace:systrace 工具只能监控特定系统调用的耗时情况
  4. Simpleperf

06 | 卡顿优化(下):如何监控应用卡顿?

应用卡顿

  1. 基于消息队列实现,通过替换 Looper 的 Printer实现
  2. 插桩(Inline Hook 在方法前后加日志)
  3. Profilo

其它监控:

  1. 帧率(使用 Choreographer 来监控应用的帧率)
  2. 生命周期监控(生命周期的耗时和调用次数)
  3. 线程监控(线程数量多少)
  4. Android Vitals(Google Play 官方的性能监控服务)

06 | 补充篇 | 卡顿优化:卡顿现场与卡顿分析

Thread 的 getState 方法获取线程状态
Thread.getAllStackTraces() 获得所有线程堆栈
SIGQUIT 信号实现

07 | 启动优化(上):从启动过程看启动速度优化

启动过程分析:

android高级开发瓶颈突破 android开发高手课_android高级开发瓶颈突破

  1. T1 预览窗口显示
  2. T2 闪屏显示
  3. T3 主页显示
  4. T4 界面可操作

08 | 启动优化(下):优化启动速度的进阶方法

  • I/O 优化
  • 数据重排(Dex类重排,Dex资源文件重排)
  • 类的加载
  • 黑科技(保活,插件化和热修复)

09 | I/O优化(上):开发工程师必备的I/O优化知识

cat /proc/meminfo:查看缓存的内存占用情况

MemTotal:    2866492 kB
MemFree:      72192 kB
Buffers:      62708 kB      // Buffer Cache
Cached:      652904 kB      // Page Cache

android高级开发瓶颈突破 android开发高手课_android_02


查看对应块设备的队列长度和使用的调度算法。

/sys/block/[disk]/queue/nr_requests      // 队列长度,一般是 128。
/sys/block/[disk]/queue/scheduler        // 调度算法

proc/self/schedstat:

se.statistics.iowait_count:IO 等待的次数
  se.statistics.iowait_sum:  IO 等待的时间

将所有 block 读写 dump 到日志文件中,这样可以通过 dmesg 命令来查看

echo 1 > /proc/sys/vm/block_dump
dmesg -c grep pid
.sample.io.test(7540): READ block 29262592 on dm-1 (256 sectors)
.sample.io.test(7540): READ block 29262848 on dm-1 (256 sectors)

通过 strace 来跟踪 I/O 相关的系统调用次数和耗时

strace -ttT -f -p [pid]
read(53, "*****************"\.\.\., 1024) = 1024       <0.000447>
read(53, "*****************"\.\.\., 1024) = 1024       <0.000084>
read(53, "*****************"\.\.\., 1024) = 1024       <0.000059>

strace 统计一段时间内所有系统调用的耗时概况

strace -c -f -p [pid]
% time     seconds  usecs/call     calls    errors  syscall
------ ----------- ----------- --------- --------- ----------------
 97.56    0.041002          21      1987             read
  1.44    0.000605          55        11             write

10 | I/O优化(中):不同I/O方式的使用场景是什么?

I/O 的三种方式

android高级开发瓶颈突破 android开发高手课_共享库_03


Page Cache 中脏页写入磁盘机制:/proc/sys/vm 文件或者 sysctl -a | grep vm

// flush 每隔 5 秒执行一次
vm.dirty_writeback_centisecs = 500  
// 内存中驻留 30 秒以上的脏数据将由 flush 在下一次执行时写入磁盘
vm.dirty_expire_centisecs = 3000 
// 指示若脏页占总物理内存 10%以上,则触发 flush 把脏数据写回磁盘
vm.dirty_background_ratio = 10
// 系统所能拥有的最大脏页缓存的总大小
vm.dirty_ratio = 20

11 | I/O优化(下):如何监控线上I/O操作?

跟据文件保存所挂载的目录的 block size 来确认 Buffer 大小
查看磁盘预读的大小,一般是 128KB

/sys/block/[disk]/queue/read_ahead_kb

统计真正的磁盘读写次数。

/proc/diskstats

块设备名字|读请求次数|读请求扇区数|读请求耗时总和....

dm-0 23525 0 1901752 45366 0 0 0 0 0 33160 57393
dm-1 212077 0 6618604 430813 1123292 0 55006889 3373820 0 921023 3805823

命令模拟 Page Cache 的释放

echo 3 > /proc/sys/vm/drop_caches

14 | 存储优化(下):数据库SQLite的使用和优化

SQL 语句的查询计划

sqlite> EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 AND b>2;
QUERY PLAN
|--SEARCH TABLE t1 USING INDEX i2 (a=? AND b>?)

15 | 网络优化(上):移动开发工程师必备的网络优化知识

UNIX 网络 I/O 模型

android高级开发瓶颈突破 android开发高手课_上下文切换_04

20 | UI 优化(上):UI 渲染的几个关键概念

android高级开发瓶颈突破 android开发高手课_物理内存_05

22 | 包体积优化(上):如何减少安装包大小?

  • ProGuard:去掉 Debug 信息或者去掉行号
  • Dex 分包
  • Dex 压缩 XZ 压缩算法和 7-Zip
  • Library 压缩
  • Library 合并与裁剪
  • 包体积监控:大小监控、依赖监控、规则监控(Matrix-ApkChecker)

安装包内容

android高级开发瓶颈突破 android开发高手课_物理内存_06

23 | 包体积优化(下):资源优化的进阶实践

AndResGuard :资源混淆、极限压缩

无用资源删除:Lint、shrinkResources、realShrinkResources

android高级开发瓶颈突破 android开发高手课_android_07


android高级开发瓶颈突破 android开发高手课_android_08

27 | 编译插桩的三种方法

  1. AspectJ
  2. ASM
  3. ReDex

35 | Native Hook 技术,天使还是魔鬼?

android高级开发瓶颈突破 android开发高手课_android高级开发瓶颈突破_09

36 | 跨平台开发的现状与应用

android高级开发瓶颈突破 android开发高手课_上下文切换_10

40 | 动态化实践

android高级开发瓶颈突破 android开发高手课_物理内存_11


android高级开发瓶颈突破 android开发高手课_共享库_12


android高级开发瓶颈突破 android开发高手课_物理内存_13


android高级开发瓶颈突破 android开发高手课_上下文切换_14