2. 线程策略与虚拟机策略:两大检测维度的职责划分

StrictMode 的检测能力被拆为两个正交策略:ThreadPolicy(线程策略) 和 VmPolicy(虚拟机策略)。前者监控主线程上的违规操作(磁盘 I/O、网络、自定义耗时等);后者监控整个虚拟机生命周期中的资源泄漏(未关闭的 Cursor、未关闭的流、Activity 泄漏、注册的 BroadcastReceiver 未注销等)。理解两者的职责边界,是精准配置 StrictMode 的前提。

2.1 ThreadPolicy:主线程“红线”监控

ThreadPolicy 关注的是“当前线程”(默认为 UI 线程)上不允许出现的耗时代码。一旦在主线程上触发磁盘读写、网络请求或自定义慢调用,StrictMode 会通过 Log 输出、弹警告对话框或直接抛异常来提示开发者。

检测维度检测开关 (flag)默认行为典型场景
磁盘读取detectDiskReads()写 Log + VMDebug 栈SharedPreferences 读取、FileInputStream
磁盘写入detectDiskWrites()同上数据库写操作、文件输出流
网络操作detectNetwork()同上HttpURLConnection、OkHttp 同步请求
自定义耗时detectCustomSlowCalls()Log 警告自定义 Runnable/方法标识
所有违规detectAll()按声明组合全局快速启用
配置范例: 在 Application#onCreate() 中启用线程策略,并将违规行为判定为异常以便快速修复。
if (BuildConfig.DEBUG) {
    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
            .detectDiskReads()
            .detectDiskWrites()
            .detectNetwork()
            .penaltyLog()        // 输出 Logcat 警告
            .penaltyDeath()      // 直接崩溃(仅限 DEBUG)
            .build());
}

2.2 VmPolicy:全局资源泄漏“扫描仪”

VmPolicy 不绑定具体线程,而是监控整个 Dalvik/ART 虚拟机的资源分配与释放是否匹配。它通过 GC 后的残留对象来判断是否发生了泄漏。

检测维度检测开关 (flag)生效时机常见泄漏原因
Activity 泄漏detectActivityLeaks()Activity.onDestroy() 后 GC静态引用、匿名内部类持有 Activity
未关闭 CursordetectLeakedClosableObjects()GC 后 finalize 触发SQLiteCursor 未 close()
未注销 ReceiverdetectLeakedRegistrationObjects()Context 销毁后 GCBroadcastReceiver 未 unregister
Sqlite 对象泄漏detectSqliteObjectLeaks()GC 后检查SQLiteStatement 未释放
文件描述符超限detectFileUriExposure()FileProvider 未配置file:// Uri 暴露
所有资源detectAll()综合检测快速启用
实战建议: VmPolicy 的 penalty 机制与 ThreadPolicy 不同,它没有 penaltyDeath()(因为泄漏检测是异步且可能误报)。通常搭配 penaltyLog() 在 Logcat 中标记,结合 adb shell dumpsys activity processes 确认泄漏实例。

2.3 职责划分:两种策略如何协同工作

ThreadPolicy 解决性能卡顿问题(ANR 的直接诱因),VmPolicy 解决资源泄漏问题(内存溢出和稳定性隐患)。两者在排查 ANR 时的侧重点不同:

  • 主线程慢操作 → ThreadPolicy 直接捕获并输出调用栈。
  • 资源泄漏导致 GC 频繁 → VmPolicy 在泄漏发生后示警,间接帮助改善 ANR(因为频繁 GC 会抢占主线程时间)。
StrictMode 两种策略职责划分示意图 线程策略与虚拟机策略职责划分 ThreadPolicy ● 绑定当前线程(默认主线程) ● 检测磁盘读/写 ● 检测网络操作 ● 检测自定义耗时调用 ● 同步触发 → 立即警告/崩溃 目标:防止主线程阻塞 直接预防 ANR VmPolicy ● 绑定整个虚拟机 ● 检测 Activity 泄漏 ● 检测未关闭的 Closable ● 检测未注销的 Receiver ● 异步触发 → Log 记录 目标:防止资源泄漏 间接预防频繁 GC 导致的 ANR 并行使用 两者互补:ThreadPolicy 抓“耗时”,VmPolicy 抓“泄漏”

2.4 常见配置错误与调试

错误案例1:只配置 ThreadPolicy 忽略 VmPolicy,导致 Cursor 泄漏长期未被发现,最终引发 OOM,而 ANR 日志中只有 GC 信息。
错误案例2:在主线程中调用 StrictMode.noteSlowCall() 但未在 Builder 中调用 .detectCustomSlowCalls(),自定义耗时检测不会生效。

调试要点:

  • 通过 adb logcat | grep StrictMode 快速过滤策略警告。
  • VmPolicy 的泄漏警告通常包含“StrictMode VmPolicy violation”标签。
  • 使用 StrictMode.allowThreadDiskReads() 临时豁免特定代码段(例如在主线程中加载小图片)。
// 临时豁免示例
StrictMode.ThreadPolicy old = StrictMode.allowThreadDiskReads();
try {
    Bitmap bmp = BitmapFactory.decodeFile(path);
} finally {
    StrictMode.setThreadPolicy(old);
}

2.5 性能影响与部署建议

StrictMode 本身会引入少量性能开销(约 0.1~0.3ms/次检测)。生产环境必须关闭具体方式:通过 BuildConfig.DEBUG 条件编译,或使用 SystemProperties 运行时开关。

部署检查清单:
// Release 构建时自动禁用
if (BuildConfig.DEBUG) {
    StrictMode.enableDefaults(); // 或自定义配置
} else {
    // 不做任何 StrictMode 初始化
}

两种策略的配置可独立开关,建议在 DEBUG 构建中同时启用 detectAll() + penaltyLog(),待稳定后再选择性增加 penaltyDeath() 加速修复。