Android性能优化第(七)篇---StrickMode严苛模式检测耗时与内存问题

本文主要是介绍Android性能优化第(七)篇---StrickMode严苛模式检测耗时与内存问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

StrictMode意思为严格模式,是用来检测程序中违例情况的开发者工具。使用一般是场景是检测主线程中本地磁盘和网络读写等耗时的操作。注意这个StrictMode是在Anroid2.3以后引入的。严格模式主要检测两大问题,一个是线程策略,即TreadPolicy,另一个是VM策略,即VmPolicy。

线程策略(ThreadPolicy)检测的内容有

  • 1、自定义的耗时调用 使用detectCustomSlowCalls()开启
  • 2、磁盘读取操作 使用detectDiskReads()开启
  • 3、磁盘写入操作 使用detectDiskWrites()开启
  • 4、网络操作 使用detectNetwork()开启

虚拟机策略(VmPolicy)检测的内容有

  • 1、Activity泄露 使用detectActivityLeaks()开启
  • 2、未关闭的Closable对象泄露 使用detectLeakedClosableObjects()开启
  • 3、泄露的Sqlite对象 使用detectLeakedSqlLiteObjects()开启
  • 4、检测实例数量 使用setClassInstanceLimit()开启

可以看到线程策略主要与异步处理相关,虚拟机策略主要与内存管理相关。setThreadPolicy()将对当前线程应用该策略。如果不指定检测函数,也可以用detectAll()来替代。penaltyLog()表示将警告输出到LogCat,你也可以使用其他或增加新的惩罚(penalty)函数,例如使用penaltyDeath()的话,一旦StrictMode消息被写到LogCat后应用就会崩溃。另外虚拟机策略(VmPolicy)不能通过一个对话框提供警告。

在线程策略(ThreadPolicy)检测的时候,有几个penalty系列方法。

  • 1、penaltyDeath(),当触发违规条件时,直接Crash掉当前应用程序。
  • 2、penaltyDeathOnNetwork(),当触发网络违规时,Crash掉当前应用程序。
  • 3、penaltyDialog(),触发违规时,显示对违规信息对话框。
  • 4、penaltyFlashScreen(),会造成屏幕闪烁,不过一般的设备可能没有这个功能。

如何使用严格模式

严格模式的开启可以放在Application或者Activity以及其他组件的onCreate方法。为了更好地分析应用中的问题,建议放在Application的onCreate方法中。设置一次就够了。

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll()//开启所有的detectXX系列方法.penaltyDialog()//弹出违规提示框.penaltyLog()//在Logcat中打印违规日志.build());requestDataFromNet();}/*** 请求数据*/private void requestDataFromNet() {URL url;try {url = new URL("http://www.baidu.com");HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.connect();BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));String lines ;StringBuilder sb = new StringBuilder();while ((lines = reader.readLine()) != null) {sb.append(lines);}Log.d("response",sb.toString());} catch (Exception e) {e.printStackTrace();}}
}

比如上面代码运行之后,就会有下面的弹窗出来警告。 

看一下logcat的日志,是在主线程中做了访问网络的操作。

12-19 17:28:54.226 2729-2729/? D/StrictMode: StrictMode policy violation; ~duration=44 ms: android.os.StrictMode$StrictModeNetworkViolation: policy=63 violation=4at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1123)at java.net.InetAddress.lookupHostByName(InetAddress.java:385)at java.net.InetAddress.getAllByNameImpl(InetAddress.java:236)at java.net.InetAddress.getAllByName(InetAddress.java:214)at libcore.net.http.HttpConnection.<init>(HttpConnection.java:70)at libcore.net.http.HttpConnection.<init>(HttpConnection.java:50)at libcore.net.http.HttpConnection$Address.connect(HttpConnection.java:340)at libcore.net.http.HttpConnectionPool.get(HttpConnectionPool.java:87)at libcore.net.http.HttpConnection.connect(HttpConnection.java:128)at libcore.net.http.HttpEngine.openSocketConnection(HttpEngine.java:316)at libcore.net.http.HttpEngine.connect(HttpEngine.java:311)at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:81)at zhangwan.wj.com.myshare.MainActivity.requestDataFromNet(MainActivity.java:35)at zhangwan.wj.com.myshare.MainActivity.onCreate(MainActivity.java:27)at android.app.Activity.performCreate(Activity.java:5104)at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1092)at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2254)at android.app.ActivityThread.access$600(ActivityThread.java:141)at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loop(Looper.java:137)at android.app.ActivityThread.main(ActivityThread.java:5069)at java.lang.reflect.Method.invokeNative(Native Method)at java.lang.reflect.Method.invoke(Method.java:511)at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)at dalvik.system.NativeStart.main(Native Method)

上面分析了是异步处理相关的例子,现在分析一个内存管相关的例子,比如检测内存泄露检测,用StrickMode怎么搞?

 public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectActivityLeaks()//检测Activity泄露.penaltyLog()//在Logcat中打印违规日志.build());UserManger instance = UserManger.getInstance(this);}}

比如上面的代码UserManger持有了Activity的引用,当反复进入Activity的时候,Activity不能被回收,导致了内存泄露,此时看Logcat。

12-20 09:57:07.626 4787-4787/? E/StrictMode: class zhangwan.wj.com.myshare.MainActivity; instances=3; limit=1android.os.StrictMode$InstanceCountViolation: class zhangwan.wj.com.myshare.MainActivity; instances=3; limit=1at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

明确告诉我们instances=3,说明泄露了3个MainActivity对象

严格模式除了可以检测Activity的内存泄露之外,还能自定义检测类的对象泄露。这个从从API 11 开始。

public
StrictMode.VmPolicy.Builder setClassInstanceLimit (Class klass, int instanceLimit)

比如,检测UserManger有没有泄露,可以这么写。

StrictMode.setVmPolicy(new VmPolicy.Builder().setClassInstanceLimit(UserManger.class, 1).penaltyLog().build());

在比如detectLeakedClosableObjects() 和 detectLeakedSqlLiteObjects(),资源没有正确关闭时回触发,detectLeakedRegistrationObjects() 用来检查 BroadcastReceiver 或者 ServiceConnection 注册类对象是否被正确释放等。

StrictMode有个更直接的办法,在部分手机上,可以在开发者选项中开启严格模式,开启之后,如果主线程中有执行时间长的操作,屏幕则会闪烁。OKStrictMode比较简单,到此结束!

这篇关于Android性能优化第(七)篇---StrickMode严苛模式检测耗时与内存问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/755140

相关文章

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

MyBatisPlus如何优化千万级数据的CRUD

《MyBatisPlus如何优化千万级数据的CRUD》最近负责的一个项目,数据库表量级破千万,每次执行CRUD都像走钢丝,稍有不慎就引起数据库报警,本文就结合这个项目的实战经验,聊聊MyBatisPl... 目录背景一、MyBATis Plus 简介二、千万级数据的挑战三、优化 CRUD 的关键策略1. 查

全面解析MySQL索引长度限制问题与解决方案

《全面解析MySQL索引长度限制问题与解决方案》MySQL对索引长度设限是为了保持高效的数据检索性能,这个限制不是MySQL的缺陷,而是数据库设计中的权衡结果,下面我们就来看看如何解决这一问题吧... 目录引言:为什么会有索引键长度问题?一、问题根源深度解析mysql索引长度限制原理实际场景示例二、五大解决

Springboot如何正确使用AOP问题

《Springboot如何正确使用AOP问题》:本文主要介绍Springboot如何正确使用AOP问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录​一、AOP概念二、切点表达式​execution表达式案例三、AOP通知四、springboot中使用AOP导出

Python中Tensorflow无法调用GPU问题的解决方法

《Python中Tensorflow无法调用GPU问题的解决方法》文章详解如何解决TensorFlow在Windows无法识别GPU的问题,需降级至2.10版本,安装匹配CUDA11.2和cuDNN... 当用以下代码查看GPU数量时,gpuspython返回的是一个空列表,说明tensorflow没有找到

解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题

《解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题》:本文主要介绍解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4... 目录未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘打开pom.XM