本文以Android App应用为例,介绍App应用接入与使用内存泄漏的完整流程。
在project级别的build.gradle
文件中,添加maven地址。
buildscript { repositories { maven { url "https://artifact.bytedance.com/repository/Volcengine/" } maven { url "https://artifact.bytedance.com/repository/byteX/" } } } allprojects { repositories { maven { url "https://artifact.bytedance.com/repository/Volcengine/" } } }
接入应用性能监控全链路版。
在project级别的build.gradle
文件的dependencies中,添加以下代码,接入插件组件辅助插桩。apm_insight_plugin
国内海外使用同一个版本。
classpath "com.volcengine:apm_insight_plugin:1.4.2"
在app module的build.gradle
文件的dependencies中,添加以下代码,根据国内应用还是海外应用选择下面两个版本的一个。
// 国内应用在dependencies中添加 implementation 'com.volcengine:apm_insight:1.5.6.cn' implementation 'com.volcengine:apm_insight_crash:1.5.1'
// 海外应用在dependencies中添加 implementation 'com.volcengine:apm_insight:1.5.7.oversea' implementation 'com.volcengine:apm_insight_crash:1.5.4.oversea'
在Application中onCreate中,添加以下代码,初始化性能相关功能。
注意
请在主线程中添加初始化性能相关功能的代码。
//必须放到Application的onCreate里面,会注册监听生命周期,不涉及数据采集和隐私合规问题 ApmInsight.getInstance().init(application); //初始化自定日志,配置自定义日志最大占用磁盘,内部一般配置20,代表最大20M磁盘占用。1.4.1版本开始存在这个api VLog.init(this,20);
启动性能监控,开始收集数据。
注意
请在用户同意隐私政策后,再调用方法收集数据。
ApmInsightInitConfig.Builder builder = ApmInsightInitConfig.builder(); //开启泄露和泄露兜底检测能力,泄露检测和泄露兜底需要分别在平台配置采样 builder.detectActivityLeak(new IActivityLeakListener() { @Override public void onActivityLeaked(Activity activity) { //activity泄露的回调 } }); ApmInsight.getInstance().start(builder.build());
在app module的build.gradle
文件最外层,添加以下代码,完成插桩。
启动分析和页面体验相关功能依赖插件插桩,需配置ApmPlugin的whiteList为自己的包名,配置后该目录下的代码会被插桩。
ApmPlugin {// 是否进行插桩 enable true// 是否在Debug包插桩,默认不插桩 enableInDebug true// DEBUG("DEBUG"), INFO("INFO"), WARN("WARN"), ERROR("ERROR");// DEBUG 级别Log会汇总所有被插桩处理的类供查看,路径 app/build/ByteX/ApmPlugin/ApmPlugin_log.txt logLevel "DEBUG"// 启动分析开关:监控App启动耗时,需要同时开启pageLoadSwitch startSwitch = true// 页面响应开关:监控Activity的生命周期耗时 pageLoadSwitch = true// 网络监控开关:监控okhttp3的网络请求 okHttp3Switch = true//插桩显示HttpUrlConnection的网络请求开关 httpUrlConnectionSwitch = true// 白名单下的包进行插桩,需要填写要插桩类所在的包名,支持前缀配置 whiteList = ["com" ]// 黑名单包下类不进行插桩,可以配置包名和类名,没有可以填空 blackList = ["com.xxx" ] }
端上开启泄漏检测和泄漏兜底处理开关后,平台也可以控制泄漏检测和泄漏兜底处理,泄漏兜底处理依赖泄漏检测。详细操作步骤,请参见SDK上报配置。
说明
请谨慎开启内存泄露兜底采样率,并逐渐增加采样率。兜底操作会把view的背景图置空,防止有不当逻辑在Activity onDestroy后依然有操作view背景图产生异常。
端上检测到泄露事件后,如果判断平台配置了泄露事件上报,会把泄露的Activity名称上报到平台,这样平台就可以查看哪个页面泄露的次数较多。但因为泄露引用链需要dump内存才能解析出来,性能影响较大,这里并不不会dump内存快照解析泄露引用链,只是作为泄露的监控指标。具体泄露引用链可以通过接入OOM崩溃时候dump内存解析出泄露排查问题。
在控制台左上角选择全部功能 > 事件管理。
在筛选区域单击Android系统,然后单击新增事件。
在新建事件页面,完成以下配置,然后单击创建。
配置项说明:
配置区域 | 配置项 | 说明 | 示例 |
---|---|---|---|
事件信息 | 事件名称 | 自定义名称,用于标识该事件。不能与已有事件名重复。 | apmplus_activity_leak_monitor |
事件描述 | 输入事件描述。 | 无 | |
系统 | 选择系统,支持选择Android和iOS。 | Android | |
标签 | 选择标签。便于查找该事件。 | 无 | |
指标/维度信息 | 名称 | 输入指标或者维度的名称。 | leak_activity |
类型 | 选择类型,支持选择指标和维度。
| 维度 | |
描述 | 输入对指标或者维度的描述。 | 无 | |
上报配置 | 规则名称 | 自定义规则名称,用于标识该规则。 | 全量采集 |
采样率 | 配置采样率。 | 100% | |
规则条件 | 配置规则,当满足该规则时上报事件。 | 无 |
如果Android客户端实现的需求有不当的代码实现,就会导致Activity泄漏。Activity的泄漏会牵连一系列的对象,特别是各种View和他们的背景图Bitmap会占据大量的内存,是内存泄漏非常重要的占比。泄漏分析支持检测上报Activity泄露情况,还可以兜底Activity泄露导致的内存泄露,即断掉View对图片的引用,减少泄露内存。
概念 | 说明 |
---|---|
什么是内存泄漏? | 在计算机中,由于疏忽或错误造成程序未能释放已经不再使用的内存,叫做内存泄漏。
如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。 |
如何检测Activity是泄露的? | 一个Activity如果已经执行了onDestroy(),那么他的生命周期已经结束,不应该被任何对象所引用。在下一次GC回收的时候应该把执行了onDestroy()的Activity回收掉。如果执行了GC依然没有被回收,则判定当前Activity有强引用,已经泄露。 |
如何判断执行了GC? | 支持代码主动触发GC,但是频繁GC对APP的整理运行并不友好,可能会造成卡顿。所以支持配置延迟检测Activity泄露,尽可能的让系统自己触发GC回收,而不是人为主动触发。 |
如何判断Activity是否被回收? | 使用 |
什么是内存泄漏兜底? | 一些泄漏的对象的生命周期已经结束,但依然存在着强引用,导致对象没有办法被GC回收。通过代码主动断开泄露对象到GC ROOT的链路,或者释放掉泄露对象的引用对象,让这些泄露对象在下次GC时候可以被回收掉,释放出内存空间,这就是内存泄露兜底。它就像一个自动扫地机器人,不断地帮您在房间清理垃圾。 |
内存泄漏兜底处理哪些对象? |
通过延时处理泄露Activity持有View树的背景图和ImageView的图片,在Activity泄露后把背景图和ImageView的图片置空,防止图片泄露。 |