匿名Thread治理 -- 字节码增强
2022-01-15 本文已影响0人
Young_Allen
背景
- 在某种场景下会无限制的创建新线程,最终导致 OOM
- 在某一时间应用内的线程数达到数百甚至上千
- 即使在空闲的时候,线程池中的线程一直在 WAITING
这些现象最终导致的问题是:Out Of Memory
治理以上问题的难点之一在于
- 研发通常匿名创建了线程
- 无法修改第三方包中匿名线程
Android 创建匿名线程主要是通过以下几种方式:
- Thread 及其子类
- Timer 及其子类
目标
给匿名线程添加className + methodName
方案
通过ASM技术,在编译期间拦截transform,对匿名线程添加className + methodName
编译前源码:
image image image编译后自动补全className + methodName:
image分析Thread相关问题时,可根据Name定位到对应线程:
image项目ASM框架参考booster,实现逻辑涉及到业务,不方便提供,不过了解了这种思路很容易也能实现
使用方法
在项目根目录中build.gradle中添加以下红色代码:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
maven { url 'http://artifactory.d.xiaomi.net/artifactory/artifactory-releases' }
}
dependencies {
classpath "com.android.tools.build:gradle:4.2.2"
classpath "com.didiglobal.booster:booster-gradle-plugin:4.0.0"
classpath 'com.mi.bytem:bytem:1.0.2-SNAPSHOT'
}
}
...
接下来在 Android 工程的 build.gradle添加以下红色代码:
plugins {
id 'com.android.application'
id 'com.didiglobal.booster'
}
android {
...
}
...
验证插件是否生效
- 编译Log是否有以下输出
- 查看app/build/intermediates/transforms/booster是否存在,并可在此目录下查看最终编译后的transforms之后的文件是否符合预期
Tips
💡💡💡💡💡💡💡💡💡💡
使用以上方式可以帮助使用者分析定位业务代码、第三方库中匿名线程问题,但本质原因还是使用者创建了匿名线程,因此最好的解决办法还是在code-review时拒绝匿名线程的代码。