Reference对象所引用的对象被GC回收时,该Reference对象将会被加入与之关联的ReferenceQueue的队列末尾
这里的Reference对象指的是Java的四种引用对象(强引用、软引用、弱引用、虚引用)
如何使用?import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
public class WeakReferenceTest {
public static void main(String[] args) {
ReferenceQueue referenceQueue = new ReferenceQueue();
Object obj = new Object();
//把obj放入weakReference,并和一个referenceQueue关联
//当obj被gc回收后,weakReference会被加入referenceQueue队列的末尾
WeakReference weakReference = new WeakReference(obj,referenceQueue);
System.out.println("盛放obj的weakReference = " + weakReference);
//把obj置空,让它没有强引用
obj = null;
Runtime.getRuntime().gc();//gc,回收obj
try{
Thread.sleep(1000);
}catch (Exception e){}
Reference findRef = null;
while((findRef = referenceQueue.poll()) !=null){
System.out.println("findRef = " +findRef);
System.out.println(findRef == weakReference);
//如果能找到上面的weakReference => 说明它盛放的obj被gc回收了
}
}
}
LeakCanary源码分析(leakcanary-2.2)
leakcanary-object-watcher-android模块的AndroidManifest.xml
AppWatcherInstaller
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
InternalAppWatcher.install(application)
return true
}
InternalAppWatcher
fun install(application: Application) {
SharkLog.logger = DefaultCanaryLog()
SharkLog.d { "Installing AppWatcher" }
//检查当前线程是否是是主线程
checkMainThread()
if (this::application.isInitialized) {
//如果LeakCanary已经加载过,直接返回
return
}
InternalAppWatcher.application = application
val configProvider = { AppWatcher.config }
//监视Activity
ActivityDestroyWatcher.install(application, objectWatcher, configProvider)
//监视Fragment
FragmentDestroyWatcher.install(application, objectWatcher, configProvider)
//调用上层模块InternalLeakCanary.invoke
onAppWatcherInstalled(application)
}
下面我们先看监视Activity的代码,ActivityDestroyWatcher
companion object {
fun install(
application: Application,
objectWatcher: ObjectWatcher,
configProvider: () -> Config
) {
//创建activityDestroyWatcher
val activityDestroyWatcher =
ActivityDestroyWatcher(objectWatcher, configProvider)
//与application绑定
application.registerActivityLifecycleCallbacks(activityDestroyWatcher.lifecycleCallbacks)
}
}
ActivityDestroyWatcher
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityDestroyed(activity: Activity) {
if (configProvider().watchActivities) {
//ObjectWatcher监视Activity
objectWatcher.watch(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
}
ObjectWatcher
@Synchronized fun watch(
watchedObject: Any,
description: String
) {
if (!isEnabled()) {
return
}
//将可回收的activity删除
removeWeaklyReachableObjects()
val key = UUID.randomUUID()
.toString()
val watchUptimeMillis = clock.uptimeMillis()
//创建KeyedWeakReference(是WeakReference的子类),绑定ReferenceQueue
val reference =
//watchedObject:activity, key:uuid, queue:ReferenceQueue
KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
SharkLog.d {
"Watching " +
(if (watchedObject is Class<*>) watchedObject.toString() else "instance of ${watchedObject.javaClass.name}") +
(if (description.isNotEmpty()) " ($description)" else "") +
" with key $key"
}
//将reference保存到watchedObjects数组中
watchedObjects[key] = reference
//启动延时5s任务
checkRetainedExecutor.execute {
moveToRetained(key)
}
}
private fun removeWeaklyReachableObjects() {
// WeakReferences are enqueued as soon as the object to which they point to becomes weakly
// reachable. This is before finalization or garbage collection has actually happened.
var ref: KeyedWeakReference?
do {
ref = queue.poll() as KeyedWeakReference?
if (ref != null) {
//删除可达对象,剩下的就是内存泄露的对象
watchedObjects.remove(ref.key)
}
} while (ref != null)
}
//延时5s任务
val watchDurationMillis: Long = TimeUnit.SECONDS.toMillis(5)
private val checkRetainedExecutor = Executor {
mainHandler.postDelayed(it, AppWatcher.config.watchDurationMillis)
}
@Synchronized private fun moveToRetained(key: String) {
//将可达activity删除
removeWeaklyReachableObjects()
val retainedRef = watchedObjects[key]
if (retainedRef != null) {
//保存当前时间作为内存泄露的时间
retainedRef.retainedUptimeMillis = clock.uptimeMillis()
//通知InternalLeakCanary发生内存泄露
onObjectRetainedListeners.forEach { it.onObjectRetained() }
}
}
InternalLeakCanary
override fun onObjectRetained() {
if (this::heapDumpTrigger.isInitialized) {
//通知heapDumpTrigger有内存泄露
heapDumpTrigger.onObjectRetained()
}
}
HeapDumpTrigger
fun onObjectRetained() {
//再次检查内存泄露
scheduleRetainedObjectCheck(
reason = "found new object retained",
rescheduling = false
)
}
private fun scheduleRetainedObjectCheck(
reason: String,
rescheduling: Boolean,
delayMillis: Long = 0L
) {
val checkCurrentlyScheduledAt = checkScheduledAt
if (checkCurrentlyScheduledAt > 0) {
val scheduledIn = checkCurrentlyScheduledAt - SystemClock.uptimeMillis()
SharkLog.d { "Ignoring request to check for retained objects ($reason), already scheduled in ${scheduledIn}ms" }
return
} else {
val verb = if (rescheduling) "Rescheduling" else "Scheduling"
val delay = if (delayMillis > 0) " in ${delayMillis}ms" else ""
SharkLog.d { "$verb check for retained objects${delay} because $reason" }
}
checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
backgroundHandler.postDelayed({
checkScheduledAt = 0
//检查泄露对象
checkRetainedObjects(reason)
}, delayMillis)
}
private fun checkRetainedObjects(reason: String) {
val config = configProvider()
// A tick will be rescheduled when this is turned back on.
if (!config.dumpHeap) {
SharkLog.d { "Ignoring check for retained objects scheduled because $reason: LeakCanary.Config.dumpHeap is false" }
return
}
var retainedReferenceCount = objectWatcher.retainedObjectCount
if (retainedReferenceCount > 0) {
//GC一次,确认所有剩余对象都是内存泄露的对象
gcTrigger.runGc()
retainedReferenceCount = objectWatcher.retainedObjectCount
}
//检查当前剩余对象的个数
if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return
//如果配置了debug不dumpHeap并且正在debug
if (!config.dumpHeapWhenDebugging && DebuggerControl.isDebuggerAttached) {
onRetainInstanceListener.onEvent(DebuggerIsAttached)
showRetainedCountNotification(
objectCount = retainedReferenceCount,
contentText = application.getString(
R.string.leak_canary_notification_retained_debugger_attached
)
)
//延时20s执行
scheduleRetainedObjectCheck(
reason = "debugger is attached",
rescheduling = true,
delayMillis = WAIT_FOR_DEBUG_MILLIS
)
return
}
val now = SystemClock.uptimeMillis()
val elapsedSinceLastDumpMillis = now - lastHeapDumpUptimeMillis
//WAIT_BETWEEN_HEAP_DUMPS_MILLIS为60s,60s内执行一次操作
if (elapsedSinceLastDumpMillis < WAIT_BETWEEN_HEAP_DUMPS_MILLIS) {
onRetainInstanceListener.onEvent(DumpHappenedRecently)
showRetainedCountNotification(
objectCount = retainedReferenceCount,
contentText = application.getString(R.string.leak_canary_notification_retained_dump_wait)
)
scheduleRetainedObjectCheck(
reason = "previous heap dump was ${elapsedSinceLastDumpMillis}ms ago (< ${WAIT_BETWEEN_HEAP_DUMPS_MILLIS}ms)",
rescheduling = true,
delayMillis = WAIT_BETWEEN_HEAP_DUMPS_MILLIS - elapsedSinceLastDumpMillis
)
return
}
SharkLog.d { "Check for retained objects found $retainedReferenceCount objects, dumping the heap" }
dismissRetainedCountNotification()
//执行dumpHeap操作
dumpHeap(retainedReferenceCount, retry = true)
}
private fun checkRetainedCount(
retainedKeysCount: Int,
retainedVisibleThreshold: Int
): Boolean {
val countChanged = lastDisplayedRetainedObjectCount != retainedKeysCount
lastDisplayedRetainedObjectCount = retainedKeysCount
if (retainedKeysCount == 0) {
SharkLog.d { "Check for retained object found no objects remaining" }
if (countChanged) {
onRetainInstanceListener.onEvent(NoMoreObjects)
showNoMoreRetainedObjectNotification()
}
//剩余对象为0
return true
}
//剩余对象低于阈值5个
if (retainedKeysCount < retainedVisibleThreshold) {
//当前应用可见或不可见时间间隔小于5s
if (applicationVisible || applicationInvisibleLessThanWatchPeriod) {
if (countChanged) {
onRetainInstanceListener.onEvent(BelowThreshold(retainedKeysCount))
}
showRetainedCountNotification(
objectCount = retainedKeysCount,
contentText = application.getString(
R.string.leak_canary_notification_retained_visible, retainedVisibleThreshold
)
)
//重新安排2s后执行checkRetainedObejcts
scheduleRetainedObjectCheck(
reason = "found only $retainedKeysCount retained objects (< $retainedVisibleThreshold while app visible)",
rescheduling = true,
delayMillis = WAIT_FOR_OBJECT_THRESHOLD_MILLIS
)
return true
}
}
return false
}
GcTrigger
object Default : GcTrigger {
override fun runGc() {
// Code taken from AOSP FinalizationTest:
// https://android.googlesource.com/platform/libcore/+/master/support/src/test/java/libcore/
// java/lang/ref/FinalizationTester.java
// System.gc() does not garbage collect every time. Runtime.gc() is
// more likely to perform a gc.
// System.gc()并不会每次执行GC,Runtime.gc()会
Runtime.getRuntime()
.gc()
enqueueReferences()
System.runFinalization()
}
LeakCanary的缺点
1.自己在分析的时候容易OOM
2.只针对Activity和Fragment进行预设埋点,我们需要自己定制源码,针对对象进行裁剪
3.只分析Retain size大的对象,或者是对内存对象裁剪,不全部加载到内存中



