一、使用
public class ExampleApplication extends Application {
public static RefWatcher getRefWatcher(Context context) {
ExampleApplication application = (ExampleApplication) context.getApplicationContext();
return application.refWatcher;
}
private RefWatcher refWatcher;
@Override public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
//监测当前应用内存泄露的是进程是否正在运行,
//如果正在运行则不用再次进行初始化,否则进行初始化操作。
return;
}
refWatcher =LeakCanary.install(this);
// Normal app init code...
}
}
LeakCanary的使用非常的简单,两行代码搞定。当然也可以主动的添加需要监听的对象;
LeakCanary.install(this);调用之后会返回一个RefWatcher对象,然后就可以调用观察分析某个对象:
public abstract class BaseFragment extends Fragment {
@Override public void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity());
refWatcher.watch(this);
}
}
我们就从这上面那两行代码开始进行分析。
二、LeakCanary.isInAnalyzerProcess(this)
public static boolean isInAnalyzerProcess(Context context) {
return isInServiceProcess(context, HeapAnalyzerService.class);
}
->LeakCanary.isInServiceProcess()
public static boolean isInServiceProcess(Context context, Class extends Service> serviceClass) {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo;
try {
//获取当前应用注册的Service信息
packageInfo = packageManager.getPackageInfo(context.getPackageName(), GET_SERVICES);
} catch (Exception e) {
CanaryLog.d(e, "Could not get package info for %s", context.getPackageName());
return false;
}
String mainProcess = packageInfo.applicationInfo.processName;
ComponentName component = new ComponentName(context, serviceClass);
ServiceInfo serviceInfo;
try {
//查找HeapAnalyzerService信息
serviceInfo = packageManager.getServiceInfo(component, 0);
} catch (PackageManager.NameNotFoundException ignored) {
// 找不到HeapAnalyzerService相应信息 返回false
return false;
}
//判断HeapAnalyzerService所在的进程名称是否和宿主进程一样
if (serviceInfo.processName.equals(mainProcess)) {
return false;
}
//判断HeapAnalyzerService是否正在运行
int myPid = android.os.Process.myPid();
ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.RunningAppProcessInfo myProcess = null;
List runningProcesses =
activityManager.getRunningAppProcesses();
if (runningProcesses != null) {
for (ActivityManager.RunningAppProcessInfo process : runningProcesses) {
if (process.pid == myPid) {
myProcess = process;
break;
}
}
}
if (myProcess == null) {
CanaryLog.d("Could not find running process for %d", myPid);
return false;
}
return myProcess.processName.equals(serviceInfo.processName);
}
这段代码相对比较简单主要是判断HeapAnalyzerService是否已经启动了,如果启动了就不用再进行初始化启动了。
三、LeakCanary.install(this)
初始化并且开始监听每个Activity销毁时是否存在内存泄露。
public static RefWatcher install(Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
3.1、LeakCanary.refWatcher()
public static AndroidRefWatcherBuilder refWatcher(Context context) {
return new AndroidRefWatcherBuilder(context);
}
3.2、AndroidRefWatcherBuilder.listenerServiceClass()
添加监听
public AndroidRefWatcherBuilder listenerServiceClass(
Class extends AbstractAnalysisResultService> listenerServiceClass) {
return heapDumpListener(new ServiceHeapDumpListener(context, listenerServiceClass));
}
创建内存回收监听器
-> ServiceHeapDumpListener()
public ServiceHeapDumpListener(Context context,
Class extends AbstractAnalysisResultService> listenerServiceClass) {
//向PageManage注册DisplayLeakService和HeapAnalyzerService
setEnabled(context, listenerServiceClass, true);
setEnabled(context, HeapAnalyzerService.class, true);
this.listenerServiceClass = checkNotNull(listenerServiceClass, "listenerServiceClass");
this.context = checkNotNull(context, "context").getApplicationContext();
}
3.3、AndroidRefWatcherBuilder.buildAndInstall()
public RefWatcher buildAndInstall() {
RefWatcher refWatcher = build();
if (refWatcher != DISABLED) {
//向PageManage注册DisplayLeakActivity
LeakCanary.enableDisplayLeakActivity(context);
//监听activity销毁事件
ActivityRefWatcher.install((Application) context, refWatcher);
}
return refWatcher;
}
3.4、 ActivityRefWatcher.install()
public static void install(Application application, RefWatcher refWatcher) {
new ActivityRefWatcher(application, refWatcher).watchActivities();
}
注册Activity销毁事件监听
-> ActivityRefWatcher.watchActivities()
public void watchActivities() {
// Make sure you don't get installed twice.
stopWatchingActivities();
application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
}
private final Application.ActivityLifecycleCallbacks lifecycleCallbacks =
new Application.ActivityLifecycleCallbacks() {
@Override public void onActivityDestroyed(Activity activity) {
//在Activity销毁会会调用这个方法
ActivityRefWatcher.this.onActivityDestroyed(activity);
}
};
}
在Activity销毁时,对销毁的Activity的进行追踪和分析。
3.5、RefWatcher.ensureGoneAsync()
private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
watchExecutor.execute(new Retryable() {
@Override public Retryable.Result run() {
return ensureGone(reference, watchStartNanoTime);
}
});
}
使用线程池进行异步分析:
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
long gcStartNanoTime = System.nanoTime();
long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
//移除已经被回收的activity实例对应的KeyedWeakReference(见3.5.1)
removeWeaklyReachableReferences();
if (debuggerControl.isDebuggerAttached()) {
// The debugger can create false leaks.
return RETRY;
}
//判断当前activity是否被回收了
if (gone(reference)) {
return DONE;
}
//发起gc
gcTrigger.runGc();
//移除已经被回收的activity实例对应的KeyedWeakReference(见3.5.1)
removeWeaklyReachableReferences();
//当 retainedKeys中还存在当前activity实例对应的KeyedWeakReference时,
//说明当前Activity已经发生内存泄漏了
if (!gone(reference)) {
long startDumpHeap = System.nanoTime();
long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
File heapDumpFile = heapDumper.dumpHeap();
if (heapDumpFile == RETRY_LATER) {
// Could not dump the heap.
return RETRY;
}
long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
//分析activity堆信息
heapdumpListener.analyze(
new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
gcDurationMs, heapDumpDurationMs));
}
return DONE;
}
3.5.1、RefWatcher.removeWeaklyReachableReferences()
private void removeWeaklyReachableReferences() {
KeyedWeakReference ref;
while ((ref = (KeyedWeakReference) queue.poll()) != null) {
retainedKeys.remove(ref.key);
}
}
这个主要判断当前Activity是否存在内存泄露。原理就是:
通过创建WeakRrefences对象,它包含一个queue,当jvm开始gc时,如果WeakRrefences包含的对象被回收,则会加入到这个queue中。那么通过这个queue就可以知道当前的这个实例是否被回收了还是没有被回收。
四、总结
原理也比较简单在触发GC时
利用了WeakRrefences和WeakRrefencesQueue判断某个对象是否已经被回收。