記錄一次使用 Android Profiler 分析內存

版權聲明:本文章原創於 RamboPan ,未經允許,請勿轉載。

記錄一次使用 Android Profiler 分析內存

最近手裏開發了一個小應用,功能也不復雜,大致功能是:

  • 加載本地的視頻及生成縮略圖,用戶選擇一個點擊按鈕進行觀看,再點擊一次結束觀看。

  • 記錄時間差,然後跳轉一個新界面,把時間差動態加載出來。

  • 點擊按鈕主動 或者 倒數30秒 後返回主菜單。

也不難,貼一個做完了的效果。

在這裏插入圖片描述

雖然這個應用不大,我們也需要嚴謹是吧,也分析下代碼中有沒有導致內存泄露的情況。
這次做個筆記。

這裏使用 Android Profiler 進行分析,分析內存中的對象是否因爲不合理的寫法,在頁面關閉後未能被回收。

先說說這個小應用,主要分爲 3 個頁面:配置頁面播放頁面結果頁面

在這裏插入圖片描述

主要是把 assets 目錄中的本地文件複製到需要使用的設備上。完成第一次使用配置。

做這種給他人使用的應用,多加一些操作說明方便他人,也給自己節省時間(別人詢問的時間)。

加載視頻以及生成縮略圖,這裏用了 LruCache 做了一層內存緩存(用戶切換視頻時加載更快),也生成了對應圖片文件做了一層硬盤緩存(下一次進入時直接讀取本地文件)。

在這裏插入圖片描述

這個界面就一個倒計時與動態顯示秒數,因爲並沒有要求特別複雜的動態顯示,直接採用間隔時間修改 TextView ,做了一個簡單的任務定時修改 TextView 。返回可以通過點擊按鈕返回,也可以是倒計時到時間返回。


我們開始通過 Android Profiler 啓動這個應用。

然後點擊 Memory 這部分。
在這裏插入圖片描述
先看第一個界面的內存分析。
在這裏插入圖片描述

因爲我點擊複製文件之後,複製了幾個較大的視頻文件。從波浪的圖形中能夠看出內存不斷使用。

每複製完成一個文件後,佔用內存變小再進行下一次增大,結束最後一次複製後和剛開始時內存佔用差不多。

這裏看着沒有問題,我們直接進入第二個界面分析。

才進入的時候,因爲需要生成縮略圖文件以及內存緩存,所以內存佔用迅速增加。

這裏使用 Dunp Java Heap 按鈕,獲取堆信息。

在這裏插入圖片描述

能看到有 PlayActivityPlayActivity$ ,這裏 PlayActivity $ 表明 PlayActivity 的某個內部對象正在引用外部的 PlayActivity

從右邊也能看出,有些 view 正在加載圖片,這次是才進入播放界面採集的堆信息,有圖片正在生成與加載肯定是正常的。

先說明下我們需要觀察的幾個參數,見下圖:

在這裏插入圖片描述

- Allocations : 代表總的實例數量。
- Shallow Size : 代表這些實例自身所佔的大小。
- Retained Size : 代表這些實例及其引用所佔的所有大小。

現在對比下上面的圖,我們只進入了一次 ResultActivity ,所以對應 PlayActivityPlayActivity$Allocations 都是 1 。

後面我們會測試幾次進入,可以再觀察這個值。

我們接着剛纔的說,耐心等上一小會,我們手動 GC 一次進行清理,再獲取堆信息。

一般應用在 GC 之後能發現明顯的內存減少。

在這裏插入圖片描述

這次能看到因爲圖片已經加載完成,所以只留下了一個 PlayActivity 實例。這裏看也是沒有什麼問題的。

(6 個 FrameImageView 是因爲主界面有 6 個場景選擇的 View。)

現在我們點擊觀看視頻,等待一段時間後,結束觀看,此處開始跳轉結果頁面。

在這裏插入圖片描述

第一個上升趨勢是點擊按鈕後視頻開始播放,第二個上升趨勢是跳轉了結果頁面。

然後我們點擊結果頁面的返回按鈕。再過一小段時間,我們點擊 GC 按鈕,再取一次堆信息。

在這裏插入圖片描述

第一個下降趨勢是點擊返回時,部分內存直接收回。第二個下降趨勢是點擊 GC 後再次釋放的內存,

從圖裏能看見,除了 ResultActivity 沒有被回收,還有一個 ResultActivity $ 1,我們點擊之後能看到有一個 mOnClickListener in View$Listener ,那麼這個代碼對應在哪呢 ?

對應在屏幕中央的返回按鈕,我使用了一個匿名的 OnClickListener


	btnBack.setOnClickListener(new View.OnClickListener() {
	    @Override
	    public void onClick(View v) {
	        finish();
	    }
	});
        

看了 ResultActivity$1 ,我們再來看 ResultActivity 這個實例,點開之後發現都是資源有關的引用。

在這裏插入圖片描述

從這來看,也沒有什麼大的問題,回收肯定會回收,只是時間會等得更久一點。

稍等一會再回來,再次點擊 GC 按鈕,只剩 PlayActivity,也符合之前的判斷。

在這裏插入圖片描述

這次測試是從結果頁面返回播放界面,等待了一會之後點擊 GC 再進行堆信息獲取。


那麼如果點擊返回之後立刻獲取堆信息會怎麼樣 ? 現在來試一試。

在這裏插入圖片描述

怎麼突然多了這麼多 ResultActivity$ !!!

既然出現了這麼多,肯定是有原因的。點開 ResultActivity$2 發現是倒數計時的 View 以及不斷倒計時的 String

因爲需要不斷更新 TextView 的文字,肯定需要一個定時的任務或者線程來執行。我這是把 TextView 和線程封裝了一下。

因爲之前已經想到了可能會提前結束,所以在 onDestroy() 方法中加入了對任務的停止,
當然放在點擊按鈕時處理也是可以的。


	@Override
	protected void onDestroy() {
	    if (mCountDownTask != null) mCountDownTask.stopTask();
	        
	    super.onDestroy();
	}
	    

所以此處產生了很多 String 對象,也算正常。再點開 ResultActivity$3

在這裏插入圖片描述

能看到有個 val$alpha ,還有剛剛的 View ,因爲這個 View 結束時會閃動一下,我這是通過修改透明度實現的,所以此處存在很多透明度值也是正常的。

還有個 ResultActivity$1 和之前是一樣的,那個匿名 OnClickListener

在這裏插入圖片描述

此時我們再點擊 GC 發現因爲倒計時 View 產生的多個對 ResultActivity 的引用已經不在了。

在這裏插入圖片描述

剩下兩個 ResultActivity$ 仍然是之前分析的匿名 OnClickListenerResultactivity 中的一些資源引用。

再次等待一會後 GC ,能看到 ResultActivity 相關的都已經回收了。

在這裏插入圖片描述


我們測試了單次(觀看視頻後跳轉結果再退回主界面) ,現在我們來多測試幾次,再獲取一次堆信息。

在這裏插入圖片描述

能看到 ResultAcitivity 相關的都多了很多,至少都是 4+,點開其中一個發現都是重複的,說明確實是因爲幾次使用增加了相關的對象,然後我們耐心等待後再 GC 一次,發現 ResultActivity 還剩一個,後面就沒再截圖了。

在這裏插入圖片描述

從這些分析暫時看出代碼中沒有內存泄露的跡象。

如果有不妥之處或不同意見,煩請留言,互相提高。


Android Profiler 參考資料:

https://developer.android.com/studio/profile/android-profiler?hl=zh-cn

https://www.youtube.com/watch?v=LGVbpobV-Yg)=

https://www.youtube.com/watch?v=O5V9ZSL0BsM&t=614s

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章