博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android内存泄露分析之StrictMode
阅读量:6235 次
发布时间:2019-06-22

本文共 4518 字,大约阅读时间需要 15 分钟。

转载请注明地址:http://blog.csdn/yincheng886337/article/details/50524709

StrictMode(严格模式)使用

StrictMode严格模式,主要用来检测程序中违例情况的开发者工具。最常用的场景就是检测主线程中本地磁盘、网络读写等耗时的操作以及Activity泄露等,但该模式不建议在Release版本开启,此外该模式无法监控JNI中的磁盘IO和网络请求且其违例情况仅供参考,需结合实际开发需求予以解决。

 

StrictMode检测什么?

主要采用采用ThreadPolicy(线程策略)和VmPolicy(Vm策略)进行检测,各策略检测内容如下:

ThreadPolicy

线程策略检测的内容有

· 自定义的耗时调用 使用 detectCustomSlowCalls() 开启

· 磁盘读取操作 使用 detectDiskReads() 开启

· 磁盘写入操作 使用 detectDiskWrites() 开启

· 网络操作 使用 detectNetwork() 开启

VmPolicy

虚拟机策略检测的内容有

· Activity泄露 使用 detectActivityLeaks() 开启

· 未关闭的Closable对象泄露 使用 detectLeakedClosableObjects() 开启

· 泄露的Sqlite对象 使用 detectLeakedSqlLiteObjects() 开启

· 检测实例数量 使用 setClassInstanceLimit() 开启

StrictMode具体使用

public class DebugUtil {      public static void startStrictModeVmPolicy(){          StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()          .detectActivityLeaks()/*检测Activity内存泄露*/          .detectLeakedClosableObjects()/*检测未关闭的Closable对象*/          .detectLeakedSqlLiteObjects() /*检测Sqlite对象是否关闭*/             /*也可以采用detectAll()来检测所有想检测的东西*/          .penaltyLog().build());      }      public static void startStrictModeThreadPolicy(){          StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()          .detectDiskReads()/*磁盘读取操作检测*/          .detectDiskWrites()/*检测磁盘写入操作*/          .detectNetwork() /*检测网络操作*/             /*也可以采用detectAll()来检测所有想检测的东西*/          .penaltyLog().build());  }  }

如果你想检测整个App或某Activity的相关泄露问题,可在Application或Activity的onCreate方法中直接调用DebugUtil中封装好的策略即可

如何查看检测结果?

只需要查看TAG为StrictMode的日志即可,如:logcat -c;logcat -s StrictMode 或者adb logcat | grep StrictMode

如何解决检测出来的问题?

针对此问题下面给出几点建议,仅供参考:

1.如果是主线程中出现文件读写违例问题,建议使用工作线程(可采用HandlerThread,IntentService、线程池或直接new Thread,必要时可结合Handler)完成,但采用工作线程在某个Activity中操作时注意线程要能正常结束,否则将导致内存泄露,相关细节后文将有表述。

2.如果是对SharedPrefrences写入操作,在API 9以上建议优先调用apply而非commit,此外需注意的是确保SharedPrefrences在单进程中使用,如果涉及跨进程数据交换,建议自己编写跨进程SharedPrefrences实现机制,否则可能导致数据不准确。

3.如果存在未关闭的Closable对象,需根据对应的stacktrace进行关闭。

4.如果SQLite对象泄露,根据对应的stacktrace进行释放。

5.注意registerBroadcast和unregisterBroadcast配对使用,对文件操作完成后记得close操作。

StrictMode使用示例

现以主线程中文件读写为例,引起违例警告的代码如下:

public void writeToExternalStorage() {          File externalStorage = Environment.getExternalStorageDirectory();          File destFile = new File(externalStorage, "dest.txt");          try {            OutputStream output = new FileOutputStream(destFile, true);              output.write("droidyue.com".getBytes());              output.flush();              output.close();          } catch (FileNotFoundException e) {                e.printStackTrace();          } catch (IOException e) {            e.printStackTrace();          }      }

StrictMode违例警告:

D/StrictMode( 9730): StrictMode policy violation; ~duration=20 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=31 violation=2              D/StrictMode( 9730):    at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1176)              D/StrictMode( 9730):    at libcore.io.BlockGuardOs.open(BlockGuardOs.java:106)              D/StrictMode( 9730):    at libcore.io.IoBridge.open(IoBridge.java:390)              D/StrictMode( 9730):    at java.io.FileOutputStream.
(FileOutputStream.java:88) D/StrictMode( 9730): at com.example.strictmodedemo.MainActivity.writeToExternalStorage(MainActivity.java:56) D/StrictMode( 9730): at com.example.strictmodedemo.MainActivity.onCreate(MainActivity.java:30) D/StrictMode( 9730): at android.app.Activity.performCreate(Activity.java:4543)

解决方法:

public void writeToExternalStorage() {          new Thread(){              @Override              public void run() {                  /*将对读写操作移至线程*/                  File externalStorage = Environment.getExternalStorageDirectory();                  File destFile = new File(externalStorage, "dest.txt");                  OutputStream output = null;                  try {                      output = new FileOutputStream(destFile, true);                      output.write("droidyue.com".getBytes());                      output.flush();                                      } catch (FileNotFoundException e) {                        e.printStackTrace();                  } catch (IOException e) {                    e.printStackTrace();                  }finally{                      /*对文件操作完成后,注意关闭*/                      if(output != null){                          output.close();                      }                  }              }          }              }

 

你可能感兴趣的文章
Web技巧(07)
查看>>
[翻译]http2-for-a-faster-web——快速了解http2
查看>>
写给自己看的面试题整理
查看>>
强力推荐开发类chrome插件
查看>>
SSM框架Spring+SpringMVC+MyBatis——详细整合教程
查看>>
利用Elasticsearch构建流量分析平台(一)
查看>>
[设计冲刺Design Sprint 核对清单]五天步骤笔记之星期一:绘制地图
查看>>
记一次Java服务频繁Full GC的排查过程
查看>>
使用 Docker 部署 Spring Boot
查看>>
从零开始写一个 Babel 插件
查看>>
给你的Flutter页面跳转加上动画
查看>>
【多图】记录下使用 koa2 搭建微信中控服务器
查看>>
Stars数量非常高的Github Page
查看>>
[译]重构源代码构建 Android TV 开发手册十四
查看>>
iOS性能监控
查看>>
Web HttpServletRequest的getRequestURL方法获取不到https协议请求问题
查看>>
JavaScript——操作符
查看>>
Visual Studio Code 变量参考
查看>>
Docker容器的未来,将继续充分利用Linux功能
查看>>
死磕 java集合之ConcurrentHashMap源码分析(一)——插入元素全解析
查看>>