1、前言
Flutter 所使用的 dart 语言具有垃圾回收机制,有垃圾回收就避免不了会内存泄漏。在 Android 平台上有个内存泄漏检测工具 LeakCanary ,它可以方便的在 debug 环境下检测当前页面是否泄漏。本文将会带你实现一个 flutter 可用的 LeakCanary,并讲述我是怎么用该工具检测出了 1.9.1 framework 上的两个泄漏。
2、Dart 中的弱引用
在具有垃圾回收的语言中,弱引用是检测对象是否泄漏的一个好方式。我们只需弱引用观测对象,等待下次 Full GC,如果 gc 之后对象为 null,说明被回收了,如果不为 null 就可能是泄漏了
Dart 语言中也有着弱引用,它叫 Expando<T>
,看下它的 api:
class Expando<T> {
external T operator [](Object object);
external void operator []=(Object object, T value);
}
你可能会好奇上述代码弱引用体现在哪里呢?其实是在 expando[key]=value
这个赋值语句上。Expando 会以弱引用的方式持有 key,这里就是弱引用的地方。
那么问题来了,这个 Expando
弱引用持有的是 key,但是本身又没有提供 getKey()
这样的 api,我们就无从下手去得知 key 这个对象是否被回收了。
为了解决这个问题,我们来看下 Expando
的具体实现,具体的代码在 expando_path.dart:
@path
class Expando<T> {
// ...
T operator [](Objet object) {
var mask = _size - 1;
var idx = object._identityHashCode & mask;
// sdk 是把 key 放到了一个 _data 数组内,这个 wp 是个 _WeakProperty
var wp = _data[idx];
// ... 省略部分代码
return wp.value;
// ... 省略部分代码
}
}
注意: 此 patch 代码不适用于 web 平台
我们可以发现这个 key 对象是放到了 _data
数组内,用了一个 _WeakProperty
来包裹,那么这个 _WeakProperty
就是关键类了,看下它实现,代…码在 weak_property.dart:
@pragma("vm:entry-point")
class _WeakProperty {
get key => _getKey();
// ... 省略部分代码
_getKey() native "WeakProperty_getKey";
// ... 省略部分代码
}
这个类有我们想要的 key
,可以用于判断对象是否还在!
怎么获取这种私有属性和变量呢?flutter 中的 dart 是不支持反射的(为了优化打包 size,关闭了反射),有没有其它办法来获取到这种私有属性呢?
答案肯定是 “有”,为了解决上述问题,我这边介绍一个 dart 自带的服务,Dart VM Service。
3、Dart vm_service
Dart VM Service (后面简称 vm_service)是 dart 虚拟机内部提供的一套 web 服务,数据传输协议是 JSON-RPC 2.0。不过我们并不需要要自己去实现数据请求解析,官方已经写好了一个可用的 dart sdk 给我们用 vm_service。
ObjRef, Obj 和 id 的作用
先介绍 vm_service 中的