国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Android 源碼淺析:Leakcanary 內(nèi)存泄漏檢測的好幫手

這篇具有很好參考價值的文章主要介紹了Android 源碼淺析:Leakcanary 內(nèi)存泄漏檢測的好幫手。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

我們一起來分析一下大名鼎鼎的 Leakcanary, 想必作為 Android 開發(fā)都多多少少接觸過,新版本的 Leakcanary 也用 Kotlin 重寫了一遍,最近詳細(xì)查看了下源碼,分享一下。

tips:本來是只想分析下內(nèi)存泄漏檢測部分,但寫著寫著就跑偏了,因?yàn)閮?nèi)存泄漏的檢測難點(diǎn)在于對對象生命周期的把控, Leakcanary 對于 Service 生命周期的把控我覺得非常值得我們學(xué)習(xí),并且在項(xiàng)目中也會用到。外加 Leakcanary 用 Kotlin 重寫,一些語法糖我平時也沒用過,就順便寫了下,整體讀下來有點(diǎn)啰嗦。

源碼版本

debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10'

內(nèi)存泄漏

本博客著重分析 leakcanary 源碼實(shí)現(xiàn)原理以及一些優(yōu)秀設(shè)計(jì),對于內(nèi)存泄漏的解釋就簡單用我自己的理解來解釋下:長生命周期對象持有短生命周期對象,當(dāng)短生命周期對象需要被回收時因其被長生命周期對象持有導(dǎo)致無法正?;厥盏那闆r;

源碼淺析

在了解其優(yōu)秀設(shè)計(jì)之前先來簡單分析下其源碼以及實(shí)現(xiàn)原理。

如需完整版的學(xué)習(xí)資料 請點(diǎn)擊免費(fèi)領(lǐng)取

檢測原理

Leakcanary 檢測內(nèi)存泄漏的原理很簡單,就是利用弱引用 WeakReference 的雙參數(shù)構(gòu)造方法

WeakReference(T referent, ReferenceQueue<? super T> q)

來檢測被弱引用的對象是否被正常回收、釋放,舉個例子:

// 定義類
class A
// 檢測的目標(biāo)對象
val obj = A()
val queue = ReferenceQueue<A>()
val weakObj = WeakReference(obj, queue)
// 觸發(fā)gc回收(注意:這樣的操作不一定可以觸發(fā)gc,具體如何觸發(fā)gc 在下面的源碼分析中有提到 leakcanary 是如何觸發(fā)gc的)
System.gc()

val tmp = queue.poll()
if (tmp === obj) {
   
    // 被回收
} else {
   
    // 未回收
}

Android 開發(fā)中的 Activity、Fragment、Service、自定義 View 都是容易發(fā)生內(nèi)存泄漏的對象,Leakcanary 所做的工作就是在合適的時機(jī)(一般是在回收時,如 Activity 的 onDestory 后)對這些對象進(jìn)行弱引用并且關(guān)聯(lián)引用隊(duì)列,根據(jù)其是否被添加到引用隊(duì)列來判斷是否發(fā)生泄漏。

關(guān)于判斷一個對象是否發(fā)生泄漏的原理上面的示例代碼已經(jīng)簡單演示,下面我們就順著源碼來看看 Leakcanary 的實(shí)現(xiàn)細(xì)節(jié)。

初始化

Leakcanary 僅需引入依賴即可完成初始化,放到現(xiàn)在這也不算多么神奇的技巧了,這是利用了 ContentProvider。

ContentProvider 的初始化時機(jī)在 Application 的 onCreate 之前,并且在 ContentProvider 的 onCreate 方法中可以獲取到 context、applicationContext。

當(dāng)項(xiàng)目引入 Leakcanary 后打包出的 apk 的清單文件中可以找到注冊了MainProcessAppWatcherInstaller,其關(guān)鍵源碼部分如下:

internal class MainProcessAppWatcherInstaller : ContentProvider() {
   
  override fun onCreate(): Boolean {
   
    val application = context!!.applicationContext as Application
    AppWatcher.manualInstall(application)
    return true
  }
  //..
}

可以看出調(diào)用了 AppWatcher.manualInstall() 進(jìn)行了初始化,其源碼如下:

AppWatcher.kt

fun manualInstall(
  application: Application,
  retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5), // 默認(rèn) 5s
  watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application) // 獲取默認(rèn)Watchers 下面詳細(xì)分析
) {
   
  // 檢查是否在主線程
  // 原理:Looper.getMainLooper().thread === Thread.currentThread()
  checkMainThread()
  // ...
  this.retainedDelayMillis = retainedDelayMillis
  // 初始化 Shark 庫
  if (application.isDebuggableBuild) {
   
    LogcatSharkLog.install()
  }
  // 這行代碼下面詳細(xì)分析
  LeakCanaryDelegate.loadLeakCanary(application)
  // 對 watchers 遍歷調(diào)用 install 
  watchersToInstall.forEach {
   
    it.install()
  }
  // 給 installCause 賦值,代表已經(jīng)初始化
  installCause = RuntimeException("manualInstall() first called here")
}

appDefaultWatchers(application)

上述初始化方法中第三個參數(shù) watchersToInstall 被賦予了默認(rèn)值,通過 appDefaultWatchers 獲取了一個 List<InstallableWatcher>,先看下 InstallableWatcher 源碼:

interface InstallableWatcher {
   
  fun install()
  fun uninstall()
}

是一個接口,定義了兩個方法看命名也能明白是安裝和卸載,接著看下 appDefaultWatchers 方法返回了什么:

fun appDefaultWatchers(
  application: Application,
  reachabilityWatcher: ReachabilityWatcher = objectWatcher // 注意這個 objectWatcher 很重要
): List<InstallableWatcher> {
   
  return listOf(
    ActivityWatcher(application, reachabilityWatcher), // 用于監(jiān)控activity內(nèi)存泄漏
    FragmentAndViewModelWatcher(application, reachabilityWatcher),// 用于監(jiān)控fragment,viewmodel 內(nèi)存泄漏
    RootViewWatcher(reachabilityWatcher),// 用于監(jiān)聽 rootview 內(nèi)存泄漏
    ServiceWatcher(reachabilityWatcher) // 用于監(jiān)聽 service 內(nèi)存泄漏
  )
}

注意上述方法的第二個參數(shù) reachabilityWatcher 默認(rèn)賦值了 objectWatcher:

val objectWatcher = ObjectWatcher(...)

先記住他是 ObjectWatcher 類的實(shí)例,并且將其傳遞給了用于檢測的各個 InstallableWatcher 實(shí)現(xiàn)類。

LeakCanaryDelegate.loadLeakCanary(application)

接著再回過頭來看一下 LeakCanaryDelegate.loadLeakCanary(application) 這句代碼,loadLeakCanary 作為 LeakCanaryDelegate 類中的一個函數(shù)類型變量,所以可以直接調(diào)用,看一下其源碼:

internal object LeakCanaryDelegate {
   
  // 延遲初始化
  val loadLeakCanary by lazy {
   
    try {
   
      // 默認(rèn)加載 InternalLeakCanary 獲取其 INSTANCE 字段
      // InternalLeakCanary 是一個 object class,編譯為 java 后會自動生成 INSTANCE
      // 就是一個單例類 這里是獲取其單例對象
      val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
      leakCanaryListener.getDeclaredField("INSTANCE")
        .get(null) as (Application) -> Unit
    } catch (ignored: Throwable) {
   
      // 出現(xiàn)異常時返回 NoLeakCanary
      NoLeakCanary
    }
  }
  // (Application) -> Unit 函數(shù)類型變量,接受一個 application 作為參數(shù)
  // 內(nèi)部都是空實(shí)現(xiàn)
  object NoLeakCanary : (Application) -> Unit, OnObjectRetainedListener {
   
    override fun invoke(application: Application) {
   }
    override fun onObjectRetained() {
   }
  }
}

一般情況下 LeakCanaryDelegate.loadLeakCanary(application) 就相當(dāng)于調(diào)用了 InternalLeakCanary,當(dāng)然 InternalLeakCanary 也是 (Application) -> Unit 的實(shí)現(xiàn)了,對你沒看錯,函數(shù)類型不僅可以聲明變量,也可以定義實(shí)現(xiàn)類,但需要實(shí)現(xiàn) invoke 方法,看下其源碼:文章來源地址http://www.zghlxwxcb.cn/news/detail-433542.html

internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener {
   
    override fun invoke(application

到了這里,關(guān)于Android 源碼淺析:Leakcanary 內(nèi)存泄漏檢測的好幫手的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 內(nèi)存泄漏檢測方式

    內(nèi)存泄漏檢測方式

    一 、 日志記錄 ????????通過宏定義重載了 malloc 和 free 函數(shù),以在分配和釋放內(nèi)存的時候記錄一些信息,包括文件名和行號,并將這些信息寫入到相應(yīng)的文件中。然后在 main 函數(shù)中演示了使用這些宏進(jìn)行內(nèi)存分配和釋放。 _malloc 函數(shù): 在分配內(nèi)存之后,創(chuàng)建一個文件名,

    2024年01月17日
    瀏覽(22)
  • 項(xiàng)目性能優(yōu)化-內(nèi)存泄漏檢測與修改

    項(xiàng)目性能優(yōu)化-內(nèi)存泄漏檢測與修改

    最近終于有空優(yōu)化一波項(xiàng)目的性能了,第一波借助Android Studio自帶的Profiler工具檢測內(nèi)存泄漏。 右側(cè)帶有綠色原點(diǎn)的就是此時運(yùn)行的Profiler的SESSION,點(diǎn)擊右側(cè)MEMORY進(jìn)入內(nèi)存監(jiān)控的詳情模塊 第三步中抓取一段時間后,會自動停止,并打開Heap Dump文件 可以看到抓取到2個會導(dǎo)致內(nèi)存

    2024年02月11日
    瀏覽(30)
  • iOS 內(nèi)存泄漏檢測 Instruments Leaks

    iOS 內(nèi)存泄漏檢測 Instruments Leaks

    Xcode 中 按住 command + I 或者菜單欄 Product – Profile 2. 雙擊 Leaks 或者按 choose,打開 Leaks 面板 3. 在顯示的 Leaks 面板中,點(diǎn)擊左上角紅色點(diǎn),即可運(yùn)行內(nèi)存檢測。 4. 在運(yùn)行過程中如果發(fā)現(xiàn)Leak Checks(如圖)出現(xiàn)紅色X說明檢測到內(nèi)存泄露,將鼠標(biāo)點(diǎn)擊Leak Checks,在下方即可看到內(nèi)存

    2024年02月01日
    瀏覽(29)
  • 手寫C語言的內(nèi)存泄漏檢測組件

    CC++語言中,棧空間有大小限制,所以程序員可以使用堆空間的內(nèi)存。堆空間的內(nèi)存是程序員自己申請的,需要程序員自己去調(diào)用釋放的操作。內(nèi)存管理是CC++程序員必須要注意的問題,其中包括了內(nèi)存泄漏,內(nèi)存泄漏的原因是程序中申請的內(nèi)存沒有進(jìn)行釋放,來看下面的例子

    2024年02月03日
    瀏覽(20)
  • Python中的內(nèi)存泄漏及其檢測方法

    一、引言 內(nèi)存泄漏是編程中常見的問題之一,它會導(dǎo)致程序在運(yùn)行過程中不斷消耗內(nèi)存,最終可能導(dǎo)致程序崩潰或性能下降。在Python中,內(nèi)存泄漏也是一個需要關(guān)注的問題。本文將詳細(xì)介紹Python中的內(nèi)存泄漏及其檢測方法,以幫助讀者更好地理解和解決這個問題。 二、Pyth

    2024年02月22日
    瀏覽(26)
  • Android之內(nèi)存泄漏與內(nèi)存溢出

    Android之內(nèi)存泄漏與內(nèi)存溢出

    內(nèi)存泄漏(memory leak):是指程序在申請內(nèi)存后,無法釋放已申請的內(nèi)存空間,導(dǎo)致系統(tǒng)無法及時回收內(nèi)存并且分配給其他進(jìn)程使用。通常少次數(shù)的內(nèi)存無法及時回收并不會到程序造成什么影響,但是如果在內(nèi)存本身就比較少獲取多次導(dǎo)致內(nèi)存無法正常回收時,就會導(dǎo)致內(nèi)存

    2024年02月13日
    瀏覽(25)
  • 如何處理Flutter內(nèi)存泄漏檢測和優(yōu)化

    如何處理Flutter內(nèi)存泄漏檢測和優(yōu)化

    處理Flutter內(nèi)存泄漏問題是構(gòu)建高性能、穩(wěn)定的應(yīng)用程序的關(guān)鍵部分之一。在本文中,我將詳細(xì)介紹如何檢測和優(yōu)化Flutter內(nèi)存泄漏問題,以確保應(yīng)用程序的良好性能和用戶體驗(yàn)。 1. 了解內(nèi)存泄漏 在深入了解如何處理Flutter內(nèi)存泄漏之前,首先需要了解什么是內(nèi)存泄漏。內(nèi)存泄

    2024年04月14日
    瀏覽(22)
  • 使用asan檢測內(nèi)存泄漏、堆棧溢出等問題

    操作過程參考:鏈接 緣起:程序在移動端崩潰,mac端復(fù)現(xiàn)不了,于是在寫個崩潰位置函數(shù)的調(diào)用demo,使用ASAN工具進(jìn)行排查。 驗(yàn)證過程 1、代碼 main.cpp 使用附加ASAN工具的方式進(jìn)行編譯: 執(zhí)行: 沒有問題,以上是驗(yàn)證過程,如有問題執(zhí)行時ASAN會提示有問題的相關(guān)位置。 介紹

    2024年02月11日
    瀏覽(28)
  • Android 內(nèi)存泄漏

    Android 內(nèi)存泄漏

    內(nèi)存泄漏:即memory leak。是指內(nèi)存空間使用完畢后無法被釋放的現(xiàn)象,雖然Java有垃圾回收機(jī)制(GC),但是對于還保持著引用, 該內(nèi)存不能再被分配使用,邏輯上卻已經(jīng)不會再用到的對象,垃圾回收器不會回收它們。 內(nèi)存溢出:即out of memory, 當(dāng)你要求分配的內(nèi)存超過了系統(tǒng)給你

    2024年02月08日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包