美文网首页
Android严格模式

Android严格模式

作者: 文泰ChrisTwain | 来源:发表于2022-10-22 14:29 被阅读0次

1.背景

为防止出现资源泄漏或者主线程发生的意外耗时网络操作或IO操作导致卡顿,Android2.3(API9)开始提供了监测接口StrictMode类,针对单个线程和虚拟机的所有对象定义了检查策略。监测到异常后日志能打印到具体的代码堆栈,便于立刻排查解决。

2.使用方式

应用启动处设置严苛模式,可在Application.onCreate()或Activity中启用监测,包含线程级别和进程级别两类监测接口

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        if (BuildConfig.DEBUG) {
            enableStrictMode();
        }
    }

    private void enableStrictMode() {
        // 监测当前线程(UI线程)上的网络、磁盘读写等耗时操作
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
             .detectDiskReads()  // 监测读磁盘
             .detectDiskWrites()  // 监测写磁盘
             .detectNetwork()      // 监测网络操作
             .detectCustomSlowCalls()  // 监测哪些方法执行慢
             .detectResourceMismatches()  // 监测资源不匹配
             .penaltyLog()   // 打印日志,也可设置为弹窗提示penaltyDialog()或者直接使进程死亡penaltyDeath()
             .penaltyDropBox()  //监测到将信息存到Dropbox文件夹 data/system/dropbox
             .build());

      // 监测VM虚拟机进程级别的Activity泄漏或者其它资源泄漏
     StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
             .detectActivityLeaks()  // 监测内存泄露情况
             .detectLeakedSqlLiteObjects()  // SqlLite资源未关闭,如cursor
             .detectLeakedClosableObjects()  // Closable资源未关闭,如文件流
             .detectCleartextNetwork()  // 监测明文网络
             .setClassInstanceLimit(MyClass.class, 1)  // 设置某个类的实例上限,可用于内存泄露提示
             .detectLeakedRegistrationObjects()  // 监测广播或者ServiceConnection是否有解注册
             .penaltyLog()
             .build());
    }
}

可按需建造需要监测的场景,也可使用Builder().detectAll()监测所有情况。
比如文件流未关闭,打印的日志提示如下,可根据堆栈找到导致问题的地方

2022-01-11 11:11:53.096 20010-20031/com.hello.myApp D/StrictMode: StrictMode policy violation: android.os.strictmode.LeakedClosableViolation: 
A resource was acquired at attached stack trace but never released. 
See java.io.Closeable for information on avoiding resource leaks.
        at android.os.StrictMode$AndroidCloseGuardReporter.report(StrictMode.java:1987)
        at dalvik.system.CloseGuard.warnIfOpen(CloseGuard.java:345)
        at java.io.FileInputStream.finalize(FileInputStream.java:503)
        at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:291)
        at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:278)
        at java.lang.Daemons$Daemon.run(Daemons.java:139)
        at java.lang.Thread.run(Thread.java:930)
     Caused by: java.lang.Throwable: Explicit termination method 'close' not called
        at dalvik.system.CloseGuard.openWithCallSite(CloseGuard.java:295)
        at dalvik.system.CloseGuard.open(CloseGuard.java:263)
        at java.io.FileInputStream.<init>(FileInputStream.java:176)
        at java.io.FileInputStream.<init>(FileInputStream.java:115)
        ... 自己代码调用栈

ps: 开发人员选项里的严格模式跟这个有差别
开发者选项中开启严格模式,已提示应用在主线程上执行长时间操作时闪烁屏幕


开发人员选项-严格模式

3.try-with-resources语句关闭资源

一种自动关闭资源的方式能更优雅处理资源关闭,JDK7中一个新的异常处理机制,在处理必须关闭的资源时,使用try-with-resources语句替代try-finally语句。
try-finally语句使用

InputStream in = null;
try {
    in = new FileInputStream(file);
    int temp;
    while ((temp = in.read()) != -1) {
        System.out.write(temp);
    }
} catch (IOException e) {
    // todo
} finally {
    in.close();
}

替换为try-with-resources语法,即try后面加括号引入资源

try (InputStream in = new FileInputStream(file)) {
    in = new FileInputStream(file);
    int temp;
    while ((temp = in.read()) != -1) {
        System.out.write(temp);
    }
} catch (IOException e) {
    // todo
}

实现AutoCloseable或Closeable接口均可使用此操作,可将实现此接口的类定义为资源,自己定义的资源也可以实现此接口。
ps: try-with-resources只能在JDK7及以上使用,必选在括号内有变量声明,JDK9之后括号内直接使用外部定义的变量即可

4.原理

(1)通过在需要监控的代码中植入代码实现此功能,比如IO中通过在open,read,write,close时进行监控,从上面监听到异常打印的日志堆栈即可看出植入的代码

android.os.StrictMode$AndroidCloseGuardReporter.report(StrictMode.java:1987)
        at dalvik.system.CloseGuard.warnIfOpen(CloseGuard.java:345)
        at java.io.FileInputStream.finalize(FileInputStream.java:503)
image.png

Object finalize()方法当GC确定不存在对该对象的有更多引用时,对象的垃圾回收器就会调用这个方法,FileInputStream将被回收时判断资源还未关闭随即提示。
(2)再如监测Acitivity泄露时,performLaunchActivity、performDestroyActivity方法中启动和回收Activity时用HashMap<Class, Integer>计数。
(3)StrictMode是建立在BlockGuard和CloseGuard之上的机制,Guard表示守卫,Block表示阻塞,在进行一些耗时操作时,譬如磁盘读写、网络操作,有一个守卫在监测着,它就是BlockGuard,如果这些耗时的操作导致主线程阻塞,BlockGuard就会发出通知,Close对应可打开的文件,在文件被打开后,也有一个守卫在监测着,它就是CloseGuard,如果没有关闭文件,则CloseGuard就会发出通知。

参考

严苛模式StrictMode使用指南
未关闭的文件流会引起内存泄露么
Java9改进的try-with-resources
try-with-resource语句使用

相关文章

  • Android严格模式

    1.背景 为防止出现资源泄漏或者主线程发生的意外耗时网络操作或IO操作导致卡顿,Android2.3(API9)开...

  • Android FileProvider 踩坑指北

    前言 从 Android N(7.0) 开始,将严格执行 StrictMode 模式。而从 Android N 开...

  • Android FileProvider 的使用

    1、前言 从 Android N(7.0) 开始,将严格执行 StrictMode 模式。而从 Android N...

  • onFileUriExposed

    App在StrictMode(严格)模式下运行模式下报的异常 定位异常方法 具体异常位置 Android官网对这个...

  • Android开发之StrictMode

    一. 简介 StrictMode(严格模式)是在Android 2.3(API 9)开始引入的类,StrictMo...

  • 面向对象-严格模式、作用域

    严格模式 js有两中开发模式:非严格模式(默认)+严格模式(“ues strict”) 严格模式:会进行更严格的代...

  • JavaScript this

    全局下this 非严格模式/严格模式 window 函数内this 非严格模式 window 严格模式 undef...

  • 开发中的严格模式

    js中有严格模式和非严格模式两种运行环境 在开发中,有非严格模式和严格模式2种开发模式 在严格模式下,会做更加严格...

  • 严格模式和非严格模式

    es6添加了严格模式("use strict")主要作用: 1.严格模式通过抛出错误来消除一些原有的静默错误。 2...

  • JS基本类型和变量

    严格模式 ECMAScripr5引入了严格模式。启用严格模式可以在顶部添加: “use strict” 严格模式下...

网友评论

      本文标题:Android严格模式

      本文链接:https://www.haomeiwen.com/subject/juvwortx.html