StrictMode检测内存泄漏
发布日期:2021-06-07 09:28:19 浏览次数:8 分类:技术文章

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

StrictMode

Android 2.3(API Level 9) 提供了一个称为严苛模式(StrictMode)的调试特性,Google称该特性已经使数百个Android上的Google应用程序受益。那它都做了什么呢?它将报告与线程与虚拟机相关的策略违例。一旦检测到策略违例(policy violation),你将获得警告,其包含了一个栈trace显示你的应用在何处发生违例。你可以强制用警告代替崩溃(crash),也可以仅将警告计入日志,让你的应用继续执行。

官方文档:

StrictMode is a developer tool which detects things you might be doing by accident and brings them to your attention so you can fix them.

StrictMode意思为严格模式,是用来检测程序中违例情况的开发者工具。

StrictMode is most commonly used to catch accidental disk or network on the application’s main thread, where UI operations are received and animations take place.

最常用的场景就是检测主线程中本地磁盘和网络读写等耗时的操作。

Keeping disk and network operations off the main thread makes for much smoother, more responsive applications. By keeping your application’s main thread responsive, you also prevent ANR dialogs from being shown to users.

在子线程做磁盘和网络操作,可以让应用更加平滑,及时响应。这样也可以避免ANR。

用严格模式,系统检测出主线程违例的情况会做出相应的反应,如日志打印,弹出对话框亦或者崩溃等。换言之,严格模式会将应用的违例细节暴露给开发者方便优化与改善。

注意:我们只需要在app的开发版本下使用 StrictMode,线上版本避免使用 StrictMode,随意需要通过 诸如 DEVELOPER_MODE 这样的配置变量来进行控制。

StrictMode通过策略方式来让你自定义需要检查哪方面的问题。主要有两种策略:

两种策略

  1. 线程策略(ThreadPolicy)
  2. 虚拟机策略(VMPolicy)

ThreadPolicy

线程策略检测的内容有:

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

VMPolicy

虚拟机策略检测的内容有:

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

如何使用StrictMode

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

if (IS_DEBUG && SDK_INT >= GINGERBREAD) {      StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() //              .detectAll() //              .penaltyLog() //              .penaltyDeath() //              .build());      StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()              .detectAll()              .penaltyLog()              .build());    }

严格模式需要在debug模式开启,不要在release版本中启用。

同时,严格模式自API 9 开始引入,某些API方法也从 API 11 引入。使用时应该注意 API 级别。

如有需要,也可以开启部分的严格模式。

查看结果

严格模式有很多种报告违例的形式,但是想要分析具体违例情况,还是需要查看日志,终端下过滤StrictMode就能得到违例的具体stacktrace信息。

adb logcat | grep StrictMode

检测内存泄漏

通常情况下,检测内存泄露,我们需要使用MAT对heap dump 文件进行分析,这种操作不困难,但也不容易。使用严格模式,只需要过滤日志就能发现内存泄露。

这里以Activity为例说明,首先我们需要开启对检测Activity泄露的违例检测。使用上面的detectAll或者detectActivityLeaks()均可。其次写一段能够产生Activity泄露的代码。

public class LeakyActivity extends Activity{
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MyApplication.sLeakyActivities.add(this); }}

MyApplication中关于sLeakyActivities的部分实现

public class MyApplication extends Application {
public static final boolean IS_DEBUG = true; public static ArrayList
sLeakyActivities = new ArrayList
();}

当我们反复进入LeakyActivity再退出,过滤StrictMode就会得到这样的日志

E/StrictMode( 2622): class com.example.strictmodedemo.LeakyActivity; instances=2; limit=1E/StrictMode( 2622): android.os.StrictMode$InstanceCountViolation: class com.example.strictmodedemo.LeakyActivity; instances=2; limit=1E/StrictMode( 2622):    at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

在我的demo中,使用官方的内存泄漏sample,即在Activity的onCreate方法中,使用匿名内部类,启动一个AsyncTask任务,这样,当Activity执行到onDestry的时候,该任务并没有停止,并且保存着一个该Activity的强引用,这样就会导致内存泄漏。

private void startAsyncTask() {        // This async task is an anonymous class and therefore has a hidden reference to the outer        // class MainActivity. If the activity gets destroyed before the task finishes (e.g. rotation),        // the activity instance will leak.        new AsyncTask
() { @Override protected Void doInBackground(Void... params) { // Do some slow work in background SystemClock.sleep(20000); return null; } }.execute(); }
@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_strict_mode);        ButterKnife.bind(this);        enabledStrictMode();    }    private void enabledStrictMode() {        if (IS_DEBUG && SDK_INT >= GINGERBREAD) {            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() //                    .detectAll() //                    .penaltyLog() //                    .penaltyDeath() //                    .build());            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()                    .detectAll()                    .penaltyLog()                    .build());        }    }    @OnClick(R.id.async_task)    public void onClick() {        startAsyncTask();    }

操作:进入StrictModeActivity中,点击按钮,然后在旋转屏幕,这时候Activity会重启,onDestroy方法执行了,但是由于匿名内部类仍然保留着Activity的一个强引用,导致资源不能释放,就多了一个Activity实例,造成了内存泄漏。通过adb logcat | grep StrictMode,可以得到相关的log:

01-10 17:16:35.501 3778-3778/com.example.hello E/StrictMode: class com.example.hello.activity.StrictModeActivity; instances=2; limit=1        android.os.StrictMode$InstanceCountViolation: class com.example.hello.activity.StrictModeActivity; instances=2; limit=1        at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

这样,开发者就可以定位到这个Activity,去优化或者解决内存泄漏的问题。

Demo地址:

参考:

转载地址:https://blog.csdn.net/Next_Second/article/details/54316143 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:使用LeakCanary源代码检测内存泄漏
下一篇:面向对象的六大原则

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年03月22日 06时27分07秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

rtsp 华为_华为多实例生成树RSTP配置详解 2019-04-21
ewb交通灯报告和文件_基于ewb平台的交通灯电路设计.doc 2019-04-21
mysql中$使用_在MySQL中使用序列的简单教程 2019-04-21
mysql alter auto increment_将MySQL列更改为AUTO_INCREMENT 2019-04-21
mysql+err+1067_MySQL 5.7 Invalid default value for 'CREATE_TIME'报错的解决方法 2019-04-21
程序中mysql添加用户_MySQL添加用户的两种方法 2019-04-21
简述mysql安装过程_mysql安装的过程 2019-04-21
后端接口重定向_不用再等后端的接口啦!这个开源项目花 2 分钟就能模拟出后端接口... 2019-04-21
学mysql需要英语水平多高_大学英语专业挂科率高吗 2019-04-21
mysql group by实现_SQL数据分析之 group by 的实现原理 2019-04-21
mysql数据库大小如何查看器_如何用SQL命令查看Mysql数据库大小 2019-04-21
python 红黑树_红黑树-Python实现 | 学步园 2019-04-21
java string 日期格式_JAVA中String.format的用法 格式化字符串,格式化数字,日期时间格式化,... 2019-04-21
php显示json,使用 PHP 获取并解析 JSON 显示在页面中 2019-04-21
js php排序表格,javascript实现对表格元素进行排序操作_javascript技巧 2019-04-21
php sspi,php 内置的 web 服务器 php -s 2019-04-21
java生成结果集向量,如何解释H2o深度学习输出向量? 2019-04-21
matlab 曲线拟合求导,如何对matlab cftool拟合得到的cfit函数求导数 2019-04-21
matlab 50hzquchu,新手求消除50HZ工频干扰陷波滤波器源程序 2019-04-21
laravel没有route.php,Laravel中的RouteCollection.php中的NotFoundHttpException 2019-04-21