說起leakcanary
大家應(yīng)該都很熟悉棺聊,問起原理應(yīng)該都知道在對象被銷毀時(shí)通過WeakReference+ReferenceQueue檢測對象是否被回收克伊,延遲二次檢測后還沒被回收則認(rèn)為是嫌疑對象训柴,然后dump heap并對其進(jìn)行分析...
但是你知道leakcanary
可以檢測哪些對象嗎揽涮?又是如何獲取這些即將銷毀的對象呢?
先說問題1的結(jié)論:
leakcanary
2.6版本之前只能對Activity,F(xiàn)ragment進(jìn)行監(jiān)控桦卒。
leakcanary
2.6版本以后增加了對ViewModel,RootView匿又,Service的監(jiān)控方灾。
至于如何檢測這些對象的銷毀時(shí)機(jī),下面以leakcanary-android:2.7
代碼為例做簡單的探討碌更。
1迎吵,初始化
眾所周知,leakcanary
從2.0版本開始就不需要手動初始化了针贬,其主要是通過ContentProvider
來實(shí)現(xiàn)免初始化:
<application>
<provider
android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
android:authorities="${applicationId}.leakcanary-installer"
android:enabled="@bool/leak_canary_watcher_auto_install"
android:exported="false" />
</application>
在其onCreate()中進(jìn)行了具體的初始化工作:
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
AppWatcher.manualInstall(application)
return true
}
接著看AppWatcher.manualInstall()
中做了什么:
fun manualInstall(
application: Application,
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
) {
...
watchersToInstall.forEach {
it.install()
}
}
刪繁就簡击费,這里主要是遍歷了watchersToInstall
并調(diào)用了每個(gè)item的install()
,那么watchersToInstall
是什么呢桦他?看它的默認(rèn)實(shí)現(xiàn)appDefaultWatchers(application)
:
fun appDefaultWatchers(
application: Application,
reachabilityWatcher: ReachabilityWatcher = objectWatcher
): List<InstallableWatcher> {
return listOf(
// 監(jiān)控Activity
ActivityWatcher(application, reachabilityWatcher),
// 監(jiān)控Fragment和ViewModel
FragmentAndViewModelWatcher(application, reachabilityWatcher),
// 監(jiān)控RootView
RootViewWatcher(reachabilityWatcher),
// 監(jiān)控Service
ServiceWatcher(reachabilityWatcher)
)
}
這里就是返回了一個(gè)包含四個(gè)Watcher組成的List
蔫巩,分別對Activity,F(xiàn)ragment快压,ViewModel圆仔,RootView,Service的銷毀進(jìn)行監(jiān)控蔫劣,拿到即將銷毀的對象通過WeakReference和ReferenceQueue方式進(jìn)行內(nèi)存泄漏的初步判斷坪郭,最后Dump HeapProfile進(jìn)行具體分析。
下面就看看這些Watcher是如何實(shí)現(xiàn)監(jiān)控對象銷毀過程的脉幢。
2歪沃,ActivityWatcher
ActivityWatcher
非常簡單,通過Application注冊Activity的生命周期回調(diào)嫌松,來監(jiān)控每一個(gè)Activity的銷毀沪曙,在Activity銷毀時(shí)通過reachabilityWatcher
將當(dāng)前Activity對象添加到監(jiān)控隊(duì)列,然后進(jìn)行具體分析萎羔。
class ActivityWatcher(
private val application: Application,
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityDestroyed(activity: Activity) {
// 監(jiān)控activity對象
reachabilityWatcher.expectWeaklyReachable(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
override fun install() {
// 注冊Activity的生命周期回調(diào)
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
}
3液走,F(xiàn)ragmentAndViewModelWatcher
這個(gè)Watcher實(shí)現(xiàn)了對Fragment和ViewModel的銷毀監(jiān)控,首先看一下對Fragment的銷毀監(jiān)控:
3.1 監(jiān)控Fragment銷毀
Fragment有三種:framework自帶的贾陷,supportv4包中的和androidx中的缘眶。因此需要對這三種情況分別處理,不過思路都是一樣的髓废,差別就在于導(dǎo)包巷懈。那么就看一下framework自帶的Fragment如何監(jiān)控。
class FragmentAndViewModelWatcher(
private val application: Application,
private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {
private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
// 添加對三種Fragment處理的Watcher
if (SDK_INT >= O) {
fragmentDestroyWatchers.add(
AndroidOFragmentDestroyWatcher(reachabilityWatcher)
)
}
...
fragmentDestroyWatchers
}
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
// 在ActivityCreate時(shí)調(diào)用fragmentDestroyWatchers中的每個(gè)Watcher
for (watcher in fragmentDestroyWatchers) {
watcher(activity)
}
}
}
override fun install() {
// 注冊Activity的生命周期
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
}
接著看一下AndroidOFragmentDestroyWatcher
中如何處理framework自帶的Fragment瓦哎。
internal class AndroidOFragmentDestroyWatcher(
private val reachabilityWatcher: ReachabilityWatcher
) : (Activity) -> Unit {
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
val view = fragment.view
if (view != null) {
// 將Fragment中的view加入監(jiān)控隊(duì)列
reachabilityWatcher.expectWeaklyReachable(
view, "${fragment::class.java.name} received Fragment#onDestroyView() callback " +
"(references to its views should be cleared to prevent leaks)"
)
}
}
override fun onFragmentDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
// 將Fragment加入監(jiān)控隊(duì)列
reachabilityWatcher.expectWeaklyReachable(
fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
)
}
}
override fun invoke(activity: Activity) {
val fragmentManager = activity.fragmentManager
// 通過fragmentManager注冊Fragment的生命周期回調(diào)
fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
}
}
使用的高階函數(shù)砸喻,直接看invoke()
柔逼,在其中獲取Activity的fragmentManager,并注冊Fragment的生命周期回調(diào)割岛。
在回調(diào)onFragmentViewDestroyed
中獲取Fragment中的view愉适,將view加入監(jiān)控隊(duì)列。
在回調(diào)onFragmentDestroyed
中將Fragment加入監(jiān)控隊(duì)列癣漆。
3.2 監(jiān)控ViewModel銷毀
在對AndroidX中Fragment監(jiān)控時(shí)實(shí)現(xiàn)了對ViewModel的監(jiān)控维咸,因?yàn)橹挥蠥ndroidX中才提供了ViewModel。代碼如下:
internal class AndroidXFragmentDestroyWatcher(
private val reachabilityWatcher: ReachabilityWatcher
) : (Activity) -> Unit {
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentCreated(
fm: FragmentManager,
fragment: Fragment,
savedInstanceState: Bundle?
) {
// 將Fragment中的ViewModel加入監(jiān)控隊(duì)列
ViewModelClearedWatcher.install(fragment, reachabilityWatcher)
}
...
}
override fun invoke(activity: Activity) {
if (activity is FragmentActivity) {
val supportFragmentManager = activity.supportFragmentManager
// 注冊Fragment生命周期回調(diào)
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
// 將activity中的ViewModel加入監(jiān)控隊(duì)列
ViewModelClearedWatcher.install(activity, reachabilityWatcher)
}
}
}
ViewModel存在于Activity和Fragment中惠爽,因此需要對兩者的ViewModel進(jìn)行監(jiān)控癌蓖,首先在invoke()
中注冊了Fragment生命周期回調(diào),并在回調(diào)的onFragmentCreated
通過ViewModelClearedWatcher
對該Fragment中的ViewModel進(jìn)行監(jiān)控婚肆,然后直接通過ViewModelClearedWatcher
對當(dāng)前Activity進(jìn)行了監(jiān)控租副。
接著看一下ViewModelClearedWatcher
是如何處理的:
internal class ViewModelClearedWatcher(
storeOwner: ViewModelStoreOwner,
private val reachabilityWatcher: ReachabilityWatcher
) : ViewModel() {
private val viewModelMap: Map<String, ViewModel>?
init {
// We could call ViewModelStore#keys with a package spy in androidx.lifecycle instead,
// however that was added in 2.1.0 and we support AndroidX first stable release. viewmodel-2.0.0
// does not have ViewModelStore#keys. All versions currently have the mMap field.
viewModelMap = try {
val mMapField = ViewModelStore::class.java.getDeclaredField("mMap")
mMapField.isAccessible = true
// 反射獲取ViewModelStore實(shí)例中的mMap對象
mMapField[storeOwner.viewModelStore] as Map<String, ViewModel>
} catch (ignored: Exception) {
null
}
}
override fun onCleared() {
// 遍歷mMap對象將其中的每個(gè)ViewModel對象加入監(jiān)控隊(duì)列
viewModelMap?.values?.forEach { viewModel ->
reachabilityWatcher.expectWeaklyReachable(
viewModel, "${viewModel::class.java.name} received ViewModel#onCleared() callback"
)
}
}
companion object {
fun install(
storeOwner: ViewModelStoreOwner,
reachabilityWatcher: ReachabilityWatcher
) {
// 創(chuàng)建ViewModelProvider并設(shè)置一個(gè)Factory,
val provider = ViewModelProvider(storeOwner, object : Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T =
// 創(chuàng)建ViewModelClearedWatcher并傳遞參數(shù)
ViewModelClearedWatcher(storeOwner, reachabilityWatcher) as T
})
provider.get(ViewModelClearedWatcher::class.java)
}
}
}
注意ViewModelClearedWatcher
是一個(gè)ViewModel,在install()
中創(chuàng)建了ViewModelClearedWatcher
的實(shí)例较性,在其初始化時(shí)反射獲取當(dāng)前ViewModelStoreOwner
對象的用于保存ViewModel的mMap
對象用僧,然后在其onCleared
時(shí)遍歷mMap
將其中的每個(gè)ViewModel對象加入監(jiān)控隊(duì)列。
3.3 小結(jié):
1赞咙,對于Fragment的監(jiān)控分了三種情況责循,分別是framework自帶的,supportv4包中的和androidx中的攀操。
2院仿,F(xiàn)ragment的監(jiān)控是在Activity創(chuàng)建時(shí),獲取當(dāng)前Activity的fragmentManager速和,通過fragmentManager添加Fragment的生命周期回調(diào)歹垫,在回調(diào)中分別將Fragment對象以及其中的View添加到監(jiān)控隊(duì)列。
3健芭,對于ViewModel的監(jiān)控需要對Activity和Fragment中的ViewModel分別進(jìn)行县钥。
4秀姐,通過當(dāng)前ViewModelStoreOwner
實(shí)例創(chuàng)建ViewModel對象慈迈,則該ViewModel對象會跟隨ViewModelStoreOwner
實(shí)例一起銷毀。
5省有,通過反射獲取當(dāng)前ViewModelStoreOwner
中用于存放ViewModel的集合mMap
痒留,在4中創(chuàng)建的ViewModel銷毀時(shí)遍歷該mMap
,將其每個(gè)對象都添加到監(jiān)控隊(duì)列中蠢沿。
4伸头,RootViewWatcher
RootViewWatcher監(jiān)測的是DecorView
,在Activity舷蟀,Dialog恤磷,ToolTip和Toast等創(chuàng)建過程中都涉及到DecorView
的創(chuàng)建面哼,那怎么獲取到這玩意的添加和銷毀呢?
熟悉View相關(guān)流程的應(yīng)該知道扫步,在ActivityThread中執(zhí)行完Activity的onResume后會將其DecorView
添加到WindowManagerGlobal
的一個(gè)集合中魔策,可以通過反射獲取到這個(gè)集合,對這個(gè)集合進(jìn)行代理即可監(jiān)聽DecorView
的添加和刪除河胎,給DecorView設(shè)置AttachStateChangeListener
即可監(jiān)聽DecorView的Attached
和Detached
狀態(tài)闯袒。
LeakCanary的代碼過于復(fù)雜,下面用簡單的代碼實(shí)現(xiàn)其大體流程:
class RootViewSpy {
fun install() {
val windowManagerClass = Class.forName("android.view.WindowManagerGlobal")
// 1游岳,反射獲取WindowManagerGlobal實(shí)例對象
val windowManagerInstance = windowManagerClass.getMethod("getInstance").invoke(null)
// 2政敢,反射獲取WindowManagerGlobal實(shí)例對象中的mViews集合
val mViewsField =
windowManagerClass.getDeclaredField("mViews").apply { isAccessible = true }
val mViews = mViewsField.get(windowManagerInstance) as ArrayList<View>
// 3,將mViews中的內(nèi)容存入代理集合中
delegatingViewList.apply { addAll(mViews) }
// 4胚迫,用代理集合替換原始mViews對象
mViewsField.set(windowManagerInstance, delegatingViewList)
}
// 代理對象
private val delegatingViewList = object : ArrayList<View>() {
override fun add(rootView: View): Boolean {
// 給DecorView添加AttachStateChange狀態(tài)監(jiān)聽
rootView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View) {
LogUtil.e("onViewAttachedToWindow")
}
override fun onViewDetachedFromWindow(v: View) {
LogUtil.e("onViewDetachedFromWindow")
}
})
return super.add(rootView)
}
}
}
對WindowManagerImpl進(jìn)行動態(tài)代理也可以監(jiān)聽DecorView的添加和刪除
小結(jié)
1喷户,反射獲取WindowManagerGlobal中用于存DecorView的集合
2,對這個(gè)集合進(jìn)行代理访锻,監(jiān)控DecorView的添加過程
3摩骨,對每個(gè)DecorView添加AttachStateChangeListener
,監(jiān)測其Attached
和Detached
過程
4朗若,由于前面已經(jīng)有了Activity的檢測恼五,RootViewWatcher主要會對Toast,ToolTip及Dialog(默認(rèn)不檢測)的RootView進(jìn)行監(jiān)測
5哭懈,ServiceWatcher
監(jiān)控服務(wù)的銷毀需要對Service的Stop流程有所了解灾馒,Service的Stop有三種情況:Activity中stopService(),Service中stopSelf()和unBindService()遣总。這三種情況通過不同方式進(jìn)入AMS睬罗,但最終都會通過Binder方式調(diào)用ApplicationThread的scheduleStopService()
方法,ApplicationThread會通過handler發(fā)送消息給ActivityThread旭斥;ActivityThread中執(zhí)行Service的Stop相關(guān)邏輯容达,最后ActivityThread會通知AMS做最后收尾工作。大體流程如下:
要監(jiān)聽Service的Stop有兩個(gè)點(diǎn):
在ActivityThread收到ApplicationThread消息時(shí)也就是上圖中的Hook點(diǎn)1垂券,通過給ActivityThread中的Handler對象添加callback來實(shí)現(xiàn)花盐,此時(shí)Service并沒有開始執(zhí)行stop相關(guān)操作,因此可以獲取其實(shí)例菇爪。
在ActivityThread中執(zhí)行完Service的Stop后會通過binder調(diào)用通知AMS完成最后的工作算芯,可以通過Hook AMS來監(jiān)聽到。此時(shí)服務(wù)已經(jīng)執(zhí)行了
onDestory()
凳宙,可能無法在獲取到其實(shí)例了熙揍,因此需要在hook點(diǎn)1處保存service實(shí)例,然后在此處獲取實(shí)例氏涩。
LeakCanary在Hook點(diǎn)1處獲取即將stop的Service的實(shí)例届囚,并通過弱引用保存有梆,然后在Hook點(diǎn)2處獲取實(shí)例的弱引用,進(jìn)而對其監(jiān)聽意系。
代碼使用了高階函數(shù)淳梦,大體如下:
class ServiceWatcher {
private val servicesToBeDestroyed = WeakHashMap<IBinder, WeakReference<Service>>()
private val activityThreadClass by lazy { Class.forName("android.app.ActivityThread") }
// 反射獲取ActivityThread實(shí)例
private val activityThreadInstance by lazy {
activityThreadClass.getDeclaredMethod("currentActivityThread").invoke(null)!!
}
// 獲取ActivityThread中的mService對象
private val activityThreadServices by lazy {
val mServicesField =
activityThreadClass.getDeclaredField("mServices").apply { isAccessible = true }
mServicesField.get(activityThreadInstance) as Map<IBinder, Service>
}
fun install() {
try {
swapActivityThreadHandlerCallback { mCallback ->
// 創(chuàng)建一個(gè)Handler的Callback對象
Handler.Callback { msg ->
if (msg.what == STOP_SERVICE) {
val key = msg.obj as IBinder
// 根據(jù)key(token)從mService中獲取Service對象
activityThreadServices[key]?.let {
onServicePreDestroy(key, it)
}
}
mCallback?.handleMessage(msg) ?: false
}
}
swapActivityManager { activityManagerInterface, activityManagerInstance ->
// 動態(tài)代理
Proxy.newProxyInstance(
activityManagerInterface.classLoader, arrayOf(activityManagerInterface)
) { _, method, args ->
if (METHOD_SERVICE_DONE_EXECUTING == method.name) {
val token = args!![0] as IBinder
if (servicesToBeDestroyed.containsKey(token)) {
// 當(dāng)調(diào)用AMS的serviceDoneExecuting方法時(shí)執(zhí)行onServiceDestroyed()
onServiceDestroyed(token)
}
}
try {
if (args == null) {
method.invoke(activityManagerInstance)
} else {
method.invoke(activityManagerInstance, *args)
}
} catch (invocationException: InvocationTargetException) {
throw invocationException.targetException
}
}
}
} catch (ignored: Throwable) {
LogUtil.e("Could not watch destroyed services")
}
}
private fun onServicePreDestroy(
token: IBinder,
service: Service
) {
LogUtil.e("onServicePreDestroy")
servicesToBeDestroyed[token] = WeakReference(service)
}
private fun onServiceDestroyed(token: IBinder) {
servicesToBeDestroyed.remove(token)?.also { serviceWeakReference ->
serviceWeakReference.get()?.let { service ->
LogUtil.e("${service::class.java.name} received Service#onDestroy() callback")
}
}
}
/**
* hook ActivityThread的handler
*/
private fun swapActivityThreadHandlerCallback(swap: (Handler.Callback?) -> Handler.Callback?) {
val mHField =
activityThreadClass.getDeclaredField("mH").apply { isAccessible = true }
val mH = mHField[activityThreadInstance] as Handler
val mCallbackField =
Handler::class.java.getDeclaredField("mCallback").apply { isAccessible = true }
// 獲取mH的mCallback
val mCallback = mCallbackField[mH] as Handler.Callback?
// 替換mH的mCallback對象
mCallbackField[mH] = swap(mCallback)
}
/**
* hook ams binder proxy
*/
private fun swapActivityManager(swap: (Class<*>, Any) -> Any) {
val singletonClass = Class.forName("android.util.Singleton")
val mInstanceField =
singletonClass.getDeclaredField("mInstance").apply { isAccessible = true }
val singletonGetMethod = singletonClass.getDeclaredMethod("get")
val (className, fieldName) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
"android.app.ActivityManager" to "IActivityManagerSingleton"
} else {
"android.app.ActivityManagerNative" to "gDefault"
}
val activityManagerClass = Class.forName(className)
val activityManagerSingletonField =
activityManagerClass.getDeclaredField(fieldName).apply { isAccessible = true }
val activityManagerSingletonInstance = activityManagerSingletonField[activityManagerClass]
// Calling get() instead of reading from the field directly to ensure the singleton is
// created.
// 獲取AMS的binder代理對象
val activityManagerInstance = singletonGetMethod.invoke(activityManagerSingletonInstance)
val iActivityManagerInterface = Class.forName("android.app.IActivityManager")
// 用動態(tài)代理對象替換原對象
mInstanceField[activityManagerSingletonInstance] =
swap(iActivityManagerInterface, activityManagerInstance!!)
}
companion object {
private const val STOP_SERVICE = 116
private const val METHOD_SERVICE_DONE_EXECUTING = "serviceDoneExecuting"
}
}
有一點(diǎn)需要注意,兩個(gè)Hook點(diǎn)的方法參數(shù)都是IBinder
類型的token
昔字,那如何根據(jù)token獲取其實(shí)例呢爆袍?查看ActivityThread代碼:
public final class ActivityThread {
...
// 保存所有Service實(shí)例及其對應(yīng)IBinder
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
...
// ActivityThread的當(dāng)前實(shí)例
private static ActivityThread sCurrentActivityThread;
...
}
其中mServices
保存所有Service實(shí)例及其對應(yīng)IBinder,sCurrentActivityThread是ActivityThread的當(dāng)前實(shí)例并且是靜態(tài)的作郭,因此可以直接反射獲取sCurrentActivityThread實(shí)例陨囊,然后可以反射獲取mServices
對象,根據(jù)Hook點(diǎn)的token
參數(shù)即可獲取Service實(shí)例夹攒。
小結(jié)
- 反射獲取ActivityThread中的
mServices
實(shí)例蜘醋,方便后面獲取每個(gè)Service的實(shí)例 - 獲取ActivityThread中的handler,給這個(gè)handler添加一個(gè)callback咏尝,即可實(shí)現(xiàn)對這個(gè)handler的hook
- 在第2步中压语,通過token參數(shù)從
mServices
中獲取即將stop的Service的實(shí)例,然后通過弱引用保存 - Hook AMS编检,在ActivityThread執(zhí)行完Service的stop操作后通知AMS時(shí)從2中的弱引用集合中獲取Service的引用胎食,將其加入監(jiān)控隊(duì)列
- 關(guān)于Hook AMS過程這里不做詳細(xì)介紹,可以參考https://juejin.cn/post/7006951885089292296
6允懂,最后
以上已經(jīng)獲取到了檢測對象銷毀的時(shí)機(jī)厕怜,接下來就是判斷這些被銷毀的對象是否發(fā)生了泄漏。至于如何dump heap蕾总,如何分析粥航,如何通知用戶等不是本文的重點(diǎn),相關(guān)的文章也挺多的生百,這里不再具體分析递雀。
LeakCanary
雖然是傻瓜式的工具,可以很方便的幫我們檢測內(nèi)存泄漏問題蚀浆,但是要想使用好他就要知道它可以檢測哪些對象的泄漏缀程。
大家都覺得反射、hook是洪水猛獸蜡坊,但LeakCanary
中卻各種反射杠输、各種hook,了解了這些思路方案對于解決一些特殊問題還是很有幫助的秕衙。
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上原文出處鏈接和本聲明僵刮。
本文鏈接:[http://www.reibang.com/p…)