项目GitHub
本文要点
- 一般使用的卡顿优化工具
- 卡顿问题概述
- 卡顿问题分析难点
- 关于CPU Profiler
- 关于Systrace
- 关于StrictMode
- 磁盘读写违例检测实战
- 实例限制检测实战
一般使用的卡顿优化工具
- CPU Profiler
- Systrace
- StrictMode
(strict adj.精确的; 绝对的; 严格的,严谨的; [植]笔直的
mode n.方式; 状况; 时尚,风尚; 调式 模式;)
卡顿问题概述
- 很多性能问题(如内存占用高、耗费流量等)都相对不容易被发现,
但是卡顿问题却是很容易被直观感受到的; - 卡顿问题较难排查、定位;
卡顿问题分析难点
- 可能的产生原因 繁杂:代码、内存、绘制、IO、【在主线程做UI处理、IO操作耗时操作】等;
- 线上卡顿问题,在线下难以复现,
卡顿问题跟用户届时的现场环境有很大的关系; - 比如,
届时用户终端的磁盘IO空间不足,影响了APP的IO写入性能,
导致APP卡顿,这样的场景有时候是很难复现的;
【最好在问题发生时候,就记录下来用户届时的场景】
关于CPU Profiler
图形的形式展示程序的执行时间、调用栈、执行次数等;
信息全面,包含了所有线程、所有方法的调用时间;
运行时开销比较严重,导致APP运行时所有函数都会不等比地变慢,可能会带偏优化方向;
-
使用方式
-
Debug.startMethodTracing();
【在需要监控的代码块
前添加(注意它有四个重载方法)】 -
Debug.stopMethodTracing();
【在需要监控的代码块
后添加】 - 生成的调试文件在sd卡:Android/data/packagename/files
- 上次在内存优化的实战中,
其实已经使用过,提到过CPU Profiler了,
这里可以看一下App内存优化 之 内存抖动解决实战!!!!!!
-
关于Systrace
监控和
跟踪Api调用
、线程运行
情况,生成Html报告
;需要在API 18以上使用,推荐TraceCompat;
-
使用方式
python systrace.py -t 10 [other-options][categories]
- 可以参考CSDN某博客;
或Android性能优化 -- Systrace工具(有option或category的参数表格) - 轻量级,开销小
- 直观反映CPU利用率
- 给出建议
关于StrictMode
严苛模式,Android提供的一种运行时检测机制;
如果在开发阶段对成千上万行的代码进行code review,
可能效率是比较低下的;
使用StrictMode之后,
系统会自动检测
出来主线程当中违例
的一些情况,
同时按照代码的配置
给出相应的反应
。方便,强大,容易被忽视
-
主要检测:线程检测策略、虚拟机检测策略
- 线程检测策略【
StrictMode.setThreadPolicy()
】:
如,
自定义的耗时调用检测,如detectCustomSlowCalls()
;
磁盘读取操作检测,detectDiskReads()
网络操作检测,detectNetwork()
【detect vt.查明,发现; 洞察; 侦察,侦查; 】 - 虚拟机策略【
StrictMode.setVmPolicy()
】:
Activity泄漏检测,detectActivityLeaks()
SqlLite对象泄漏检测,detectLeakedSqlLiteObjects()
限制实例数量检测,setClassInstanceLimit(要限制的类实例,限制的数量)
- 线程检测策略【
具体使用:
可以在Activity
或者Application
的onCreate()
中调用StrictMode的方法:
private boolean DEV_MODE = true;
private void initStrictMode() {
if (DEV_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectCustomSlowCalls() //API等级11,使用StrictMode.noteSlowCode
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()// or .detectAll() for all detectable problems
.penaltyLog() //在Logcat 中打印违规异常信息
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.setClassInstanceLimit(NewsItem.class, 1)
.detectLeakedClosableObjects() //API等级11
.penaltyLog()
.build());
}
}
【调试技巧】
设置一个DEV_MODE
标志位:
只有在线下开发的环境时将之设置为true,才会使进程打开StrictMode
;【检测策略的调用】
detect开头的方法,
都是StrictMode提供的检测策略,
调用过了,则StrictMode
便会进行相应的检测和反应;-
【响应方式配置】
penaltyLog()
【penalty n.惩罚,刑罚,害处】是出现违规后用log打印出来,即指定StrictMode
的响应方式,
StrictMode
除了打印log的方式,
还有其他响应方式,
如penaltyDeath()
可以让APP直接崩溃掉,
penaltyDialog()
可以弹出一个Dialog等!!!!!!!!! 实战一下:
磁盘读写违例检测(log的响应方式
):
/**
* 模拟内存泄露的Activity
*/
public class MemoryLeakActivity extends AppCompatActivity implements CallBack{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_memoryleak);
ImageView imageView = findViewById(R.id.iv_memoryleak);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.splash);
imageView.setImageBitmap(bitmap);
CallBackManager.addCallBack(this);
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.penaltyLog()
.build());
findViewById(R.id.iv_memoryleak).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
writeToExternalStorage();
}
});
}
/**
* 文件系统的操作
*/
public void writeToExternalStorage() {
try {
File externalStorage = Environment.getExternalStorageDirectory();
File mbFile = new File(externalStorage, "xxx.txt");
if (mbFile.exists()){
mbFile.createNewFile();
}
OutputStream output = new FileOutputStream(mbFile, true);
output.write("www.wooyun.org".getBytes());
output.flush();
output.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
CallBackManager.removeCallBack(this);
}
@Override
public void dpOperate() {
// do sth
}
}
Dialog
的响应方式:以上IO违例的原因就是
在主线程做了IO操作了
,
这显然是不行的,需要开一个子线程给它整!
-
实例限制检测:
public class TestApp extends Application {
static MemoryLeakActivity i = new MemoryLeakActivity();
static MemoryLeakActivity j = new MemoryLeakActivity();
@Override
public void onCreate() {
super.onCreate();
//实例限制检测 测试
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.setClassInstanceLimit(MemoryLeakActivity.class, 1)
.detectLeakedClosableObjects() //API等级11
.penaltyLog()
.build());
}
}