<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] ## Memory Profiler `Memory Profiler`是`Profiler` 中的其中一個版塊,`Profiler` 是 `Android Studio` 為我們提供的性能分析工具,使用 `Profiler` 能分析應用的 `CPU`、內存、網絡以及電量的使用情況。 使用`Memory`可以檢測以下功能 1.查看內存曲線及內存占用情況 2.可以定位是否存在內存抖動問題 3.堆轉儲(`Dump Java Heap`)可檢測出內存泄漏的對象 ![](https://img.kancloud.cn/c8/65/c8652b7c610b836fa9895571f3281e55_1240x761.png) 關于`Memory Profiler`的具體使用就不在此綴述了,想要了解的可參考:[什么是 Memory Profiler?](https://juejin.cn/post/6844903897958449166#heading-48 "https://juejin.cn/post/6844903897958449166#heading-48") * **Java**:從 Java 或 Kotlin 代碼分配的對象內存。 * **Native**:從 C 或 C++ 代碼分配的對象內存。 即使您的應用中不使用 C++,您也可能會看到此處使用的一些原生內存,因為 Android 框架使用原生內存代表您處理各種任務,如處理圖像資源和其他圖形時,即使您編寫的代碼采用 Java 或 Kotlin 語言。 * **Graphics**:圖形緩沖區隊列向屏幕顯示像素(包括 GL 表面、GL 紋理等等)所使用的內存。 (請注意,這是與 CPU 共享的內存,不是 GPU 專用內存。) * **Stack**: 您的應用中的原生堆棧和 Java 堆棧使用的內存。 這通常與您的應用運行多少線程有關。 * **Code**:您的應用用于處理代碼和資源(如 dex 字節碼、已優化或已編譯的 dex 碼、.so 庫和字體)的內存。 * **Other**:您的應用使用的系統不確定如何分類的內存。 ## showmap 這對于我們來說非常有用,可以確定進程中哪些庫占用內存比較多 ~~~ dumpsys meminfo com.sangfor.pocket ps | grep com.sangfor.pocket su showmap [pid] ~~~ ## Memory Analyzer Tool `MAT`工具可以幫助開發者定位導致內存泄漏的對象,以及發現大的內存對象,然后解決內存泄漏并通過優化內存對象,以達到減少內存消耗的目的。 比起`Memory Profiler`,`MAT`使用起來更加麻煩,同時現在`Memory Profiler`功能也越來越強大了,所以我現在已經很少使用`MAT`了 如果想要更多地了解`MAT`,也可以參考:[什么是Memory Analyzer Tool](https://juejin.cn/post/6844903897958449166#heading-52 "https://juejin.cn/post/6844903897958449166#heading-52") ## LeakCanary eakCanary是一個內存泄漏檢測的框架,默認只會檢測Activity的泄漏,如果需要檢測其他類,可以使用LeakCanary.install返回的RefWatcher,調用RefWatcher.watch(obj)就可以觀測obj對象是否出現泄漏。 ### 基本原理 LeakCanary 采用的是 Reference + ReferenceQueue來檢測一個對象是否被回收,大概需要幾個步驟: * 創建一個引用隊列 queue * 創建 Refrence 對象,并關聯引用隊列 queue * 在 reference 被回收的時候,refrence 會被添加到 queue 中 ### 基本流程 ![](https://img.kancloud.cn/1d/37/1d3759080e64e45409577643ce1505d5_862x675.png) #### 檢測泄露 觀察對象:`Activity`,`Fragment`,`RootView`,`Service 1. 傳入的觀察對象都會被存儲在`watchedObjects`中 2. 會為每個`watchedObject`生成一個`KeyedWeakReference`弱引用對象并與一個`queue`關聯,當對象被回收時,該弱引用對象將進入`queue`當中 3. 在檢測過程中,我們會調用多次`removeWeaklyReachableObjects`,將已回收對象從`watchedObjects`中移除 4. 如果`watchedObjects`中沒有移除對象,證明它沒有被回收,那么就會調用`moveToRetained` #### 觸發堆快照,生成`hprof`文件 1. 如果`retainedObjectCount`數量大于0,則進行一次`GC`,避免額外的`Dump` 2. 默認情況下,如果`retainedReferenceCount<5`,不會進行`Dump`,節省資源 3. 如果兩次`Dump`之間時間少于60s,也會直接返回,避免頻繁`Dump` 4. 調用`heapDumper.dumpHeap()`進行真正的`Dump`操作 5. `Dump`之后,要刪除已經處理過了的引用 6. 調用`HeapAnalyzerService.runAnalysis`對結果進行分析 分析`hprof`文件的工作主要是在`HeapAnalyzerService`類中完成的 關于`Hprof`文件的解析細節,就需要牽扯到`Hprof`二進制文件協議,通過閱讀協議文檔,`hprof`的二進制文件結構大概如下: ![](https://img.kancloud.cn/7f/9e/7f9e33fbe3cad99283d8ee58bd184cdf_968x220.png) 解析流程如下所示: ![](https://img.kancloud.cn/36/08/3608ff9adc07a3071e8cb7b010863a68_193x586.png) 簡要說下流程: 1.解析文件頭信息,得到解析開始位置 2.根據頭信息創建`Hprof`文件對象 3.構建內存索引 4.使用`hprof`對象和索引構建`Graph`對象 5.查找可能泄漏的對象與`GCRoot`間的引用鏈來判斷是否存在泄漏(使用廣度優先算法在`Graph`中查找) ### 為什么`LeakCanary`不能用于線上? 1. 每次內存泄漏以后,都會生成一個`.hprof`文件,然后解析,并將結果寫入`.hprof.result`。增加手機負擔,引起手機卡頓等問題。 2. 多次調用`GC`,可能會對線上性能產生影響 3. 同樣的泄漏問題,會重復生成 `.hprof` 文件,重復分析并寫入磁盤。 4.`. hprof`文件較大,信息回撈成問題。 了解了這些問題,我們可以嘗試提出一些解決方案: 1. 可以根據手機信息來設定一個內存閾值 `M` ,當已使用內存小于 `M` 時,如果此時有內存泄漏,只將泄漏對象的信息放入內存當中保存,不生成`.hprof`文件。當已使用大于 `M` 時,生成`.hprof`文件 2. 當引用鏈路相同時,可根據實際情況去重。 3. 不直接回撈`.hprof`文件,可以選擇回撈分析的結果 4. 可以嘗試將已泄漏對象存儲在數據庫中,一個用戶同一個泄漏只檢測一次,減少對用戶的影響 ## ResourceCanary ### LeakCanary的缺陷 LeakCanary分析可見其對 Activity 是否泄漏的判斷依賴VM會將可回收的對象加入 WeakReference 關聯的 ReferenceQueue 這一特性,Matrix發現這中做法在個別系統上可能存在誤報,原因大致如下: * VM 并沒有提供強制觸發 GC 的 API ,通過 System.gc()或 Runtime.getRuntime().gc()只能“建議”系統進行 GC ,如果系統忽略了我們的 GC 請求,可回收的對象就不會被加入 ReferenceQueue * 將可回收對象加入 ReferenceQueue 需要等待一段時間,LeakCanary 采用延時 100ms 的做法加以規避,但似乎并不絕對管用 * 監測邏輯是異步的,如果判斷 Activity 是否可回收時某個 Activity 正好還被某個方法的局部變量持有,就會引起誤判 * 若反復進入泄漏的 Activity ,LeakCanary 會重復提示該 Activity 已泄漏 ### ResourceCanary的改進 對此做了以下改進: * 增加一個一定能被回收的“哨兵”對象,用來確認系統確實進行了GC * 直接通過WeakReference.get()來判斷對象是否已被回收,避免因延遲導致誤判 * 若發現某個Activity無法被回收,再重復判斷3次,且要求從該Activity被記錄起有2個以上的Activity被創建才認為是泄漏,以防在判斷時該Activity被局部變量持有導致誤判 * 對已判斷為泄漏的Activity,記錄其類名,避免重復提示該Activity已泄漏 ### 修復系統潛在內存泄漏 Matrix ResourceCanary 還針對常見的系統內存泄漏做了針對性的修改。 [InputMethodManager 導致的泄漏](https://www.jianshu.com/p/62e498075e56) [Drawable泄露](https://www.jianshu.com/p/914888735ce5) [【帶著問題學】關于LeakCanary2.0你應該知道的知識點](https://juejin.cn/post/6968084138125590541) [探索 Android 內存優化方法](https://juejin.cn/post/6844903897958449166)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看