首先從LeakCanary的使用開(kāi)始講,接著會(huì)到底層分析源碼邏輯
kotlin新版本如何使用
dependencies {
// debugImplementation because LeakCanary should only run in debug builds.
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
}
只需要這樣一步就搞定了.
默認(rèn)監(jiān)測(cè)哪些泄漏
官方網(wǎng)站的說(shuō)明,無(wú)侵入式依賴,會(huì)自動(dòng)給注入如下幾個(gè)模塊的內(nèi)存泄漏監(jiān)聽(tīng)
LeakCanary automatically detects leaks of the following objects:
destroyed Activity instances
destroyed Fragment instances
destroyed fragment View instances
cleared ViewModel instances
整體工作流程
它會(huì)經(jīng)過(guò)下面4個(gè)步驟來(lái)完成所有的工作.
- Detecting retained objects. 監(jiān)測(cè)保留未被回收的對(duì)象
- Dumping the heap. 轉(zhuǎn)儲(chǔ)堆區(qū)
- Analyzing the heap. 分析堆區(qū)
- Categorizing leaks. 堆泄漏進(jìn)行分來(lái)
監(jiān)測(cè)未被回收的對(duì)象
在前臺(tái)可見(jiàn)的時(shí)候,是監(jiān)聽(tīng)到有5個(gè)未回收的對(duì)象就會(huì)開(kāi)始dump
在后臺(tái)不可見(jiàn)的時(shí)候,是監(jiān)聽(tīng)到有1個(gè)未被回收的對(duì)象就會(huì)開(kāi)始dump.
2秒鐘監(jiān)測(cè)一次,dump的周期是5秒鐘一次.
轉(zhuǎn)儲(chǔ)堆
當(dāng)達(dá)到上面的閾值情況下,就會(huì)觸發(fā)dump,
生成.hprof文件
分析堆區(qū)
現(xiàn)在是通過(guò)Shark來(lái)分析
泄漏分類
################################
步入正題,死磕源碼.
編譯后的文件里會(huì)有自動(dòng)注入一些provider和activity.
如圖所示
1: ProcessLifecycleOwnerInitializer
androidx.lifecycle.ProcessLifecycleOwnerInitializer
這是安卓系統(tǒng)自帶的一個(gè)ContentProvider
在onCreate方法里主要做了2個(gè)操作
LifecycleDispatcher.init(getContext());
ProcessLifecycleOwner.init(getContext());
1.1: LifecycleDispatcher
//底層會(huì)在application中把這個(gè)callback納入application的維護(hù)范疇內(nèi)
((Application) context.getApplicationContext())
.registerActivityLifecycleCallbacks(new DispatcherActivityCallback());
在注意看DispatcherActivityCallback中其實(shí)就做了一個(gè)事情
@VisibleForTesting
static class DispatcherActivityCallback extends EmptyActivityLifecycleCallbacks {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
//核心就是這句了.
ReportFragment.injectIfNeededIn(activity);
}
..........省略.......................
}
上面的回調(diào)Callback 是Application中的一個(gè)接口<ActivityLifecycleCallbacks>,同時(shí)Application中維護(hù)了一個(gè)ArrayList<ActivityLifecycleCallbacks>
@UnsupportedAppUsage
private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
new ArrayList<ActivityLifecycleCallbacks>();
1.2: ProcessLifecycleOwner
static void init(Context context) {
sInstance.attach(context);
}
void attach(Context context) {
mHandler = new Handler();
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
Application app = (Application) context.getApplicationContext();
//核心還是下面這行代碼了 注冊(cè)activity的生命周期回調(diào)
app.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
@Override
public void onActivityPreCreated(@NonNull Activity activity,
@Nullable Bundle savedInstanceState) {
activity.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
.......省略.......
onActivityPostStarted
.......省略.......
onActivityPostResumed
.......省略.......
});
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT < 29) {
ReportFragment.get(activity).setProcessListener(mInitializationListener);
}
}
.......省略.......
});
}
**總結(jié): 上面的2個(gè)生命周期注冊(cè)回調(diào) ,最終都是在Application類中處理的.
public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
synchronized (mActivityLifecycleCallbacks) {
mActivityLifecycleCallbacks.add(callback);
}
}
public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
synchronized (mActivityLifecycleCallbacks) {
mActivityLifecycleCallbacks.remove(callback);
}
}
2: LeakCanaryFileProvider
leakcanary.internal.LeakCanaryFileProvider
這個(gè)類我也沒(méi)看懂具體看嘛的, 大概意思就是操作file類時(shí)使用到.
3: MainProcessAppWatcherInstaller
leakcanary.internal.MainProcessAppWatcherInstaller
這個(gè)類也是集成了ContentProvider, 替代了以前老版本LeackCanary手動(dòng)install, 在這個(gè)類的onCreate方法中會(huì)自動(dòng)執(zhí)行如下操作[神來(lái)之筆]
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
AppWatcher.manualInstall(application)
return true
}
3.1: 核心代碼
@JvmOverloads
fun manualInstall(
application: Application,
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
) {
//校驗(yàn)當(dāng)前是否在主線程 Looper.getMainLooper().thread === Thread.currentThread()
checkMainThread()
if (isInstalled) {
throw IllegalStateException(
"AppWatcher already installed, see exception cause for prior install call", installCause
)
}
check(retainedDelayMillis >= 0) {
"retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
}
installCause = RuntimeException("manualInstall() first called here")
this.retainedDelayMillis = retainedDelayMillis
if (application.isDebuggableBuild) {
//debug模式 打開(kāi)日志開(kāi)關(guān)
LogcatSharkLog.install()
}
// Requires AppWatcher.objectWatcher to be set
LeakCanaryDelegate.loadLeakCanary(application)
watchersToInstall.forEach {
it.install()
}
}
3.2: 反射加載InternalLeakCanary
@Suppress("UNCHECKED_CAST")
val loadLeakCanary by lazy {
try {
val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
leakCanaryListener.getDeclaredField("INSTANCE")
.get(null) as (Application) -> Unit
} catch (ignored: Throwable) {
NoLeakCanary
}
}
上面?zhèn)鲄s Application會(huì)執(zhí)行到invoke方法
internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener {
..................省略................
override fun invoke(application: Application) {
_application = application
//校驗(yàn)是否開(kāi)啟了只在debug模式使用. 設(shè)計(jì)原理只給debug時(shí)候使用
checkRunningInDebuggableBuild()
//創(chuàng)建AppWatcher對(duì)象 同時(shí)設(shè)置監(jiān)聽(tīng)
AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
//GC回收工具
val gcTrigger = GcTrigger.Default
val configProvider = { LeakCanary.config }
//創(chuàng)建異步線程
val handlerThread = HandlerThread(LEAK_CANARY_THREAD_NAME)
handlerThread.start()
//異步線程用于后臺(tái)服務(wù)
val backgroundHandler = Handler(handlerThread.looper)
heapDumpTrigger = HeapDumpTrigger(
application, backgroundHandler, AppWatcher.objectWatcher, gcTrigger,
configProvider
)
//監(jiān)聽(tīng)?wèi)?yīng)用是否可見(jiàn)的狀態(tài) 可見(jiàn)和不可見(jiàn) retained的閾值不一樣 5 ---1
application.registerVisibilityListener { applicationVisible ->
this.applicationVisible = applicationVisible
//通知更新 如果可能話這里會(huì)觸發(fā)轉(zhuǎn)儲(chǔ)堆
heapDumpTrigger.onApplicationVisibilityChanged(applicationVisible)
}
//監(jiān)聽(tīng)onResume onPause
registerResumedActivityListener(application)
//創(chuàng)建桌面快捷圖標(biāo) 點(diǎn)擊直接進(jìn)入LeakActivity
addDynamicShortcut(application)
mainHandler.post {
backgroundHandler.post {
SharkLog.d {
//校驗(yàn)是否可以dump 如果可以dump的話 則發(fā)送notification的廣播
when (val iCanHasHeap = HeapDumpControl.iCanHasHeap()) {
is Yup -> application.getString(R.string.leak_canary_heap_dump_enabled_text)
is Nope -> application.getString(
R.string.leak_canary_heap_dump_disabled_text, iCanHasHeap.reason()
)
}
}
}
}
綜上所述:通過(guò)Android里ContentProvider的特有機(jī)制,自動(dòng)觸發(fā)install操作,在install操作中再通過(guò)類的反射去invoke執(zhí)行.
- 校驗(yàn)是否只開(kāi)啟debug模式使用
- 創(chuàng)建Watcher對(duì)象并監(jiān)聽(tīng)
- 創(chuàng)建GC回收器
- 創(chuàng)建后臺(tái)異步線程
- 監(jiān)聽(tīng)?wèi)?yīng)用可見(jiàn)與否,并調(diào)用不同的閾值策略進(jìn)行dump heap
- 創(chuàng)建桌面快捷圖標(biāo)
3.3: 不同的監(jiān)聽(tīng)器自動(dòng)注入
在AppWatcher的注冊(cè)里面最后3行 有很關(guān)鍵的動(dòng)作,如下
watchersToInstall.forEach {
it.install()
}
watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
四大金剛正式登場(chǎng)
fun appDefaultWatchers(
application: Application,
reachabilityWatcher: ReachabilityWatcher = objectWatcher
): List<InstallableWatcher> {
return listOf(
ActivityWatcher(application, reachabilityWatcher),
FragmentAndViewModelWatcher(application, reachabilityWatcher),
RootViewWatcher(reachabilityWatcher),
ServiceWatcher(reachabilityWatcher)
)
}
很多朋友反饋LeakCanary老版本功能有限,只監(jiān)聽(tīng)Activity和Fragment, 不能監(jiān)聽(tīng)Service, 這次給安排上了.
3.3.1: ActivityWatcher
繼承InstallableWatcher接口 只有install和unInstall2個(gè)方法, 通過(guò)聲明一個(gè)全局變量來(lái)做下面的操作
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityDestroyed(activity: Activity) {
//watchObject 和 description 這個(gè)描述會(huì)Log日志
reachabilityWatcher.expectWeaklyReachable(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}
override fun install() {
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
3.3.2: FragmentAndViewModelWatcher
這里面底層其實(shí)還是依賴于Activity, 同時(shí)還細(xì)分兼容為如下的
Android8.0及以上的
Android x系列的Fragment
Android support系列的fragment
//定義List<Activity>的集合
private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
//大于等于8.0版本的AndroidOFragmentDestroyWatcher
if (SDK_INT >= O) {
fragmentDestroyWatchers.add(
AndroidOFragmentDestroyWatcher(reachabilityWatcher)
)
}
//AndroidX 里的Fragment
getWatcherIfAvailable(
ANDROIDX_FRAGMENT_CLASS_NAME,
ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
reachabilityWatcher
)?.let {
fragmentDestroyWatchers.add(it)
}
//support系列里的Fragment
getWatcherIfAvailable(
ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
reachabilityWatcher
)?.let {
fragmentDestroyWatchers.add(it)
}
fragmentDestroyWatchers
}
fragmentDestroyWatchers 的使用
private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
for (watcher in fragmentDestroyWatchers) {
watcher(activity)
}
}
}
3.3.2.1: AndroidOFragmentDestroyWatcher
import android.app.Fragment
import android.app.FragmentManager
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
val view = fragment.view
if (view != null) {
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
) {
reachabilityWatcher.expectWeaklyReachable(
fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
)
}
}
//底層執(zhí)行 通過(guò)寄存的Activity獲取到對(duì)應(yīng)的FragmentManager 設(shè)置生命周期回調(diào)
override fun invoke(activity: Activity) {
val fragmentManager = activity.fragmentManager
fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
}
3.3.2.2: AndroidXFragmentDestroyWatcher 和上面的有區(qū)別
和AndroidOFragmentDestroyWatcher寫(xiě)法一樣,唯一就是導(dǎo)入的fragment包不一樣 ,以及多了2個(gè)重寫(xiě)的方法處理
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
//比androidOFragmentDestroyWatcher多了下面這些處理
override fun onFragmentCreated(
fm: FragmentManager,
fragment: Fragment,
savedInstanceState: Bundle?
) {
ViewModelClearedWatcher.install(fragment, reachabilityWatcher)
}
override fun onFragmentViewDestroyed......省略同AndroidOFragmentDestroyWatcher里..... }
override fun onFragmentDestroyed......省略同AndroidOFragmentDestroyWatcher里..... }
override fun invoke(activity: Activity) {
if (activity is FragmentActivity) {
val supportFragmentManager = activity.supportFragmentManager
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
//比androidOFragmentDestroyWatcher多了下面這一行
ViewModelClearedWatcher.install(activity, reachabilityWatcher)
}
}
通過(guò)Androidx 里的ViewModel
companion object {
fun install(
storeOwner: ViewModelStoreOwner,
reachabilityWatcher: ReachabilityWatcher
) {
val provider = ViewModelProvider(storeOwner, object : Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T =
ViewModelClearedWatcher(storeOwner, reachabilityWatcher) as T
})
provider.get(ViewModelClearedWatcher::class.java)
}
}
3.3.2.3: AndroidSupportFragmentDestroyWatcher
和AndroidOFragmentDestroyWatcher一樣,唯一就是引用的Fragment包不一樣
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import android.support.v4.app.FragmentManager
綜上所述,在fragmentWatcher處理的時(shí)候由區(qū)分兼容處理,最終通過(guò)Fragment依賴的Activity中fragmentManager進(jìn)行生命周期管理.
3.3.3: RootViewWatcher
主要處理View相關(guān)的,前提是View不依附于Activity/popWindow, 以及項(xiàng)目中配置的是否支持彈窗
private val listener = OnRootViewAddedListener { rootView ->
val trackDetached = when(rootView.windowType) {
PHONE_WINDOW -> {
when (rootView.phoneWindow?.callback?.wrappedCallback) {
// Activities are already tracked by ActivityWatcher
//如果是依附于activity的就不處理
is Activity -> false
//如果是彈窗里的 則根據(jù)配置文件來(lái)覺(jué)得
is Dialog -> {
// Use app context resources to avoid NotFoundException
// https://github.com/square/leakcanary/issues/2137
val resources = rootView.context.applicationContext.resources
resources.getBoolean(R.bool.leak_canary_watcher_watch_dismissed_dialogs)
}
// Probably a DreamService
else -> true
}
}
// Android widgets keep detached popup window instances around.
//依賴于pop window的也不處理
POPUP_WINDOW -> false
TOOLTIP, TOAST, UNKNOWN -> true
}
//可溯源追蹤的就執(zhí)行如下
if (trackDetached) {
rootView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
val watchDetachedView = Runnable {
reachabilityWatcher.expectWeaklyReachable(
rootView, "${rootView::class.java.name} received View#onDetachedFromWindow() callback"
)
}
override fun onViewAttachedToWindow(v: View) {
mainHandler.removeCallbacks(watchDetachedView)
}
override fun onViewDetachedFromWindow(v: View) {
mainHandler.post(watchDetachedView)
}
})
}
}
3.3.4: ServiceWatcher
弱引用關(guān)聯(lián)
private val servicesToBeDestroyed = WeakHashMap<IBinder, WeakReference<Service>>()
反射創(chuàng)建
private val activityThreadClass by lazy { Class.forName("android.app.ActivityThread") }
private val activityThreadInstance by lazy {
activityThreadClass.getDeclaredMethod("currentActivityThread").invoke(null)!!
}
private val activityThreadServices by lazy {
val mServicesField =
activityThreadClass.getDeclaredField("mServices").apply { isAccessible = true }
@Suppress("UNCHECKED_CAST")
mServicesField[activityThreadInstance] as Map<IBinder, Service>
}
service這里面的核心源碼暫時(shí)沒(méi)看懂, 大概能知道是就是有反射調(diào)用IActivityManager
install方法里的核心源碼貼一下
try {
swapActivityThreadHandlerCallback { mCallback ->
uninstallActivityThreadHandlerCallback = {
swapActivityThreadHandlerCallback {
mCallback
}
}
Handler.Callback { msg ->
// https://github.com/square/leakcanary/issues/2114
// On some Motorola devices (Moto E5 and G6), the msg.obj returns an ActivityClientRecord
// instead of an IBinder. This crashes on a ClassCastException. Adding a type check
// here to prevent the crash.
if (msg.obj !is IBinder) {
return@Callback false
}
if (msg.what == STOP_SERVICE) {
val key = msg.obj as IBinder
activityThreadServices[key]?.let {
onServicePreDestroy(key, it)
}
}
mCallback?.handleMessage(msg) ?: false
}
}
swapActivityManager { activityManagerInterface, activityManagerInstance ->
uninstallActivityManager = {
swapActivityManager { _, _ ->
activityManagerInstance
}
}
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)) {
onServiceDestroyed(token)
}
}
try {
if (args == null) {
method.invoke(activityManagerInstance)
} else {
method.invoke(activityManagerInstance, *args)
}
} catch (invocationException: InvocationTargetException) {
throw invocationException.targetException
}
}
}
} catch (ignored: Throwable) {
SharkLog.d(ignored) { "Could not watch destroyed services" }
}
綜上,我們知道 為什么新版本leakCanary只要依賴就行. 因?yàn)樯厦娑际亲詣?dòng)給處理了的.
4: 接著分析轉(zhuǎn)儲(chǔ)堆區(qū)
我們?cè)贏ppWatcher類里面維護(hù)著一個(gè)ObjectWatcher類
class ObjectWatcher constructor(
private val clock: Clock,
private val checkRetainedExecutor: Executor,
/**
* Calls to [watch] will be ignored when [isEnabled] returns false
*/
private val isEnabled: () -> Boolean = { true }
) : ReachabilityWatcher {
4.1: 在 AppWatcher 類里面如下
@Volatile
var retainedDelayMillis = RETAINED_DELAY_NOT_SET
val objectWatcher = ObjectWatcher(
clock = { SystemClock.uptimeMillis() },
checkRetainedExecutor = {
check(isInstalled) {
"AppWatcher not installed"
}
//重要操作 發(fā)送延遲操作的任務(wù)
mainHandler.postDelayed(it, retainedDelayMillis)
},//傳
isEnabled = { true }
),
isEnabled = { true }
上面所提到的handler就是主線程的handler
internal val mainHandler by lazy { Handler(Looper.getMainLooper()) }
在InternalLeakCanary的invoke執(zhí)行方法里面,有監(jiān)測(cè)的時(shí)候發(fā)送Notification的操作
5: NotificationReceiver
這個(gè)類主要負(fù)責(zé)接收廣播事件 DUMP_HEAP的操作,
5.1: 在上面的3.3步驟中是可以看到發(fā)送廣播的處理
backgroundHandler.post {
SharkLog.d {
//校驗(yàn)是否可以dump 如果可以dump的話 則發(fā)送notification的廣播
when (val iCanHasHeap = HeapDumpControl.iCanHasHeap()) {
is Yup -> application.getString(R.string.leak_canary_heap_dump_enabled_text)
is Nope -> application.getString(
R.string.leak_canary_heap_dump_disabled_text, iCanHasHeap.reason()
)
}
}
}
5.2 在HenapDumpControl類中
fun iCanHasHeap(): ICanHazHeap {
........省略代碼.........
synchronized(this) {
if (::latest.isInitialized && dumpHeap is Yup && latest is Nope) {
//dump的調(diào)度處理
InternalLeakCanary.scheduleRetainedObjectCheck()
}
latest = dumpHeap
}
return dumpHeap
}
5.3: 在INternalLeakCanary中
fun scheduleRetainedObjectCheck() {
if (this::heapDumpTrigger.isInitialized) {
heapDumpTrigger.scheduleRetainedObjectCheck()
}
}
5.4 在HeapDumpTrigger中
fun scheduleRetainedObjectCheck(
delayMillis: Long = 0L
) {
val checkCurrentlyScheduledAt = checkScheduledAt
if (checkCurrentlyScheduledAt > 0) {
return
}
checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
backgroundHandler.postDelayed({
checkScheduledAt = 0
//檢查是否需要dump的地方 根據(jù)需要的時(shí)候就發(fā)送廣播出去
checkRetainedObjects()
}, delayMillis)
}
5.6 在廣播中接收處理
override fun onReceive(
context: Context,
intent: Intent
) {
when (intent.action) {
DUMP_HEAP.name -> {
//具體的執(zhí)行看下面5.7
InternalLeakCanary.onDumpHeapReceived(forceDump = false)
}
CANCEL_NOTIFICATION.name -> {
// Do nothing, the notification has auto cancel true.
}
else -> {
SharkLog.d { "NotificationReceiver received unknown intent action for $intent" }
}
}
}
5.7: InternalLeakCanary類中的Dump接收處理
fun onDumpHeapReceived(forceDump: Boolean) {
if (this::heapDumpTrigger.isInitialized) {
heapDumpTrigger.onDumpHeapReceived(forceDump)
}
}
5.8 在HeapDumpTrigger中的處理
fun onDumpHeapReceived(forceDump: Boolean) {
backgroundHandler.post {
//取消notify提示
dismissNoRetainedOnTapNotification()
//手動(dòng)執(zhí)行GC 底層調(diào)用 Runtime.getRuntime().gc()
gcTrigger.runGc()
val retainedReferenceCount = objectWatcher.retainedObjectCount
if (!forceDump && retainedReferenceCount == 0) {
....省略代碼.......
return@post
}
SharkLog.d { "Dumping the heap because user requested it" }
//重要操作
dumpHeap(retainedReferenceCount, retry = false, "user request")
}
}
5.9 dumpHeap的處理
private fun dumpHeap(
retainedReferenceCount: Int,
retry: Boolean,
reason: String
) {
//創(chuàng)建存儲(chǔ)dump 文件的 目錄
val directoryProvider =
InternalLeakCanary.createLeakDirectoryProvider(InternalLeakCanary.application)
//在dump文件夾創(chuàng)建新的dump文件 目錄context.cacheDir
val heapDumpFile = directoryProvider.newHeapDumpFile()
val durationMillis: Long
try {
//發(fā)送事件 當(dāng)前的事件唯一id
InternalLeakCanary.sendEvent(DumpingHeap(currentEventUniqueId))
if (heapDumpFile == null) {
throw RuntimeException("Could not create heap dump file")
}
saveResourceIdNamesToMemory()
val heapDumpUptimeMillis = SystemClock.uptimeMillis()
//UUID為key 的一個(gè)弱引用因
KeyedWeakReference.heapDumpUptimeMillis = heapDumpUptimeMillis
durationMillis = measureDurationMillis {
configProvider().heapDumper.dumpHeap(heapDumpFile)
}
if (heapDumpFile.length() == 0L) {
throw RuntimeException("Dumped heap file is 0 byte length")
}
lastDisplayedRetainedObjectCount = 0
lastHeapDumpUptimeMillis = SystemClock.uptimeMillis()
objectWatcher.clearObjectsWatchedBefore(heapDumpUptimeMillis)
currentEventUniqueId = UUID.randomUUID().toString()
InternalLeakCanary.sendEvent(HeapDump(currentEventUniqueId, heapDumpFile, durationMillis, reason))
5.10 LeakCanary類中的事件集合
val eventListeners: List<EventListener> = listOf(
LogcatEventListener,
ToastEventListener,
LazyForwardingEventListener {
if (InternalLeakCanary.formFactor == TV) TvEventListener else NotificationEventListener
},
when {
RemoteWorkManagerHeapAnalyzer.remoteLeakCanaryServiceInClasspath ->
RemoteWorkManagerHeapAnalyzer
WorkManagerHeapAnalyzer.workManagerInClasspath -> WorkManagerHeapAnalyzer
else -> BackgroundThreadHeapAnalyzer
}
),
5.10.1: RemoteWorkManagerHeapAnalyzer
override fun onEvent(event: Event) {
if (event is HeapDump) {
val application = InternalLeakCanary.application
val heapAnalysisRequest =
OneTimeWorkRequest.Builder(RemoteHeapAnalyzerWorker::class.java).apply {
val dataBuilder = Data.Builder()
.putString(ARGUMENT_PACKAGE_NAME, application.packageName)
.putString(ARGUMENT_CLASS_NAME, REMOTE_SERVICE_CLASS_NAME)
setInputData(event.asWorkerInputData(dataBuilder))
with(WorkManagerHeapAnalyzer) {
addExpeditedFlag()
}
}.build()
SharkLog.d { "Enqueuing heap analysis for ${event.file} on WorkManager remote worker" }
val workManager = WorkManager.getInstance(application)
//入棧 執(zhí)行workQueue
workManager.enqueue(heapAnalysisRequest)
}
最終調(diào)用HeapAnalysis中的幾個(gè)數(shù)據(jù)類 HeapAnalysisFailure HeapAnalysisSuccess,里面的toString()方法就是拼接的 我們?cè)贚eakCanary中看到的錯(cuò)誤記錄.
摘要部分代碼
data class HeapAnalysisFailure(
override val heapDumpFile: File,
override val createdAtTimeMillis: Long,
override val dumpDurationMillis: Long = DUMP_DURATION_UNKNOWN,
override val analysisDurationMillis: Long,
/**
* An exception wrapping the actual exception that was thrown.
*/
val exception: HeapAnalysisException
) : HeapAnalysis() {
override fun toString(): String {
return """====================================
HEAP ANALYSIS FAILED
You can report this failure at https://github.com/square/leakcanary/issues
Please provide the stacktrace, metadata and the heap dump file.
====================================
STACKTRACE
$exception====================================
METADATA
Build.VERSION.SDK_INT: ${androidSdkInt()}
Build.MANUFACTURER: ${androidManufacturer()}
LeakCanary version: ${leakCanaryVersion()}
Analysis duration: $analysisDurationMillis ms
Heap dump file path: ${heapDumpFile.absolutePath}
Heap dump timestamp: $createdAtTimeMillis
===================================="""
}
5.10.2: WorkManagerHeapAnalyzer
和5.10.1有些類似 步驟更少
override fun onEvent(event: Event) {
if (event is HeapDump) {
val heapAnalysisRequest = OneTimeWorkRequest.Builder(HeapAnalyzerWorker::class.java).apply {
setInputData(event.asWorkerInputData())
addExpeditedFlag()
}.build()
SharkLog.d { "Enqueuing heap analysis for ${event.file} on WorkManager remote worker" }
val application = InternalLeakCanary.application
WorkManager.getInstance(application).enqueue(heapAnalysisRequest)
}
}
5.10.3: BackgroundThreadHeapAnalyzer
override fun onEvent(event: Event) {
if (event is HeapDump) {
heapAnalyzerThreadHandler.post {
val doneEvent = AndroidDebugHeapAnalyzer.runAnalysisBlocking(event) { event ->
InternalLeakCanary.sendEvent(event)
}
InternalLeakCanary.sendEvent(doneEvent)
}
}
}
以上: LeakCanary的依賴 監(jiān)聽(tīng) dump 及分析都基本上理清了.
6 PlumberInstaller
leakcanary.internal.PlumberInstaller
另外加餐補(bǔ)充這個(gè), 這個(gè)類的作用主要是反射調(diào)用不同版本不同手機(jī)廠商 對(duì)有些api是否支持到.
主要針對(duì)不同機(jī)型 不同版本,有些特殊的場(chǎng)景會(huì)導(dǎo)致Leak的時(shí)候,在Activity銷毀的時(shí)候手動(dòng)置為null方便回收.
AndroidLeakFixes.applyFixes(application)
這個(gè)分析是在后臺(tái)通過(guò)單一線程池執(zhí)行的
Executors.newSingleThreadScheduledExecutor
舉個(gè)例子,比如 這里面就有針對(duì)三星設(shè)備 且不是19到21之間的版本
反射TextView中的mLastHoveredView字段
override fun apply(application: Application) {
if (MANUFACTURER != SAMSUNG || SDK_INT !in 19..21) {
return
}
backgroundExecutor.execute {
val field: Field
try {
field = TextView::class.java.getDeclaredField("mLastHoveredView")
field.isAccessible = true
} catch (ignored: Exception) {
SharkLog.d(ignored) { "Could not fix the $name leak" }
return@execute
}
application.onActivityDestroyed {
try {
field.set(null, null)
} catch (ignored: Exception) {
SharkLog.d(ignored) { "Could not fix the $name leak" }
}
}
}
}
},
LeakActivity
leakcanary.internal.activity.LeakActivity
我們打開(kāi)金絲雀圖標(biāo)展示的就是這個(gè)Activity.
導(dǎo)入.hprof文件
private fun importHprof(fileUri: Uri) {
try {
contentResolver.openFileDescriptor(fileUri, "r")
?.fileDescriptor?.let { fileDescriptor ->
val inputStream = FileInputStream(fileDescriptor)
InternalLeakCanary.createLeakDirectoryProvider(this)
.newHeapDumpFile()
?.let { target ->
inputStream.use { input ->
target.outputStream()
.use { output ->
input.copyTo(output, DEFAULT_BUFFER_SIZE)
}
}
InternalLeakCanary.sendEvent(
HeapDump(
uniqueId = UUID.randomUUID().toString(),
file = target,
durationMillis = -1,
reason = "Imported by user"
)
)
}
}
} catch (e: IOException) {
SharkLog.d(e) { "Could not imported Hprof file" }
}
}
RequestStoragePermissionActivity
主要就是申請(qǐng)權(quán)限使用的.
以上就是整體的分析過(guò)程.
- 從設(shè)計(jì)模式來(lái)看,使用到了工廠模式(Wacher和分析器)
- 巧妙運(yùn)用ContentProvider特性達(dá)到無(wú)侵入式 一行代碼接入
- 相比老版本,新增了RootView及Service的監(jiān)測(cè)
注意事項(xiàng): 這個(gè)官方聲明只能在debug模式.
才疏學(xué)淺,歡迎探討.