项目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
- **上次在内存优化的实战中,**
关于Systrace
- 监控和**
跟踪Api调用
**、**线程运行
**情况,生成**Html报告
**; - 需要在API 18以上使用,推荐TraceCompat;
- 使用方式
- `python systrace.py -t 10 [other-options][categories]`
- 可以参考[CSDN某博客](https://links.jianshu.com/go?to=https://blog.csdn.net/songzi1228/article/details/97893123#systrace); 或
关于StrictMode
- 严苛模式,Android提供的一种运行时检测机制;
如果在开发阶段对成千上万行的代码进行code review,
可能效率是比较低下的;
使用StrictMode之后,
系统会**
自动检测
**出来主线程当中**违例
**的一些情况, 同时按照**代码的配置
**给出**相应的反应
**。 - 方便,强大,容易被忽视
- 主要检测:线程检测策略、虚拟机检测策略
- **线程检测策略【****`StrictMode.setThreadPolicy()`****】:**
代码语言:javascript复制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());
}
}