導航:首頁 > 操作系統 > android測試內存泄露

android測試內存泄露

發布時間:2023-02-11 16:08:55

1. 如何用MAT分析android程序的內存泄露

1.TraceView 1)功能:用於熱點分析和性能優化,分析每個函數佔用的CPU時間,調用次數,函數調用關系等 2)方法: a)在程序代碼中加入追蹤開關 import android.os.Debug; …… android.os.Debug.startMethodTracing(「/data/tmp/test」);// 先建/data/tmp目錄 ……// 被追蹤的程序段 android.os.Debug.stopMethodTracing(); b)編譯,運行後,設備端生成/data/tmp/test.trace文件 c)把trace文件復制到PC端 $ adb pull /data/tmp/test.trace ./ d)使用android自帶工具分析trace文件 $ANDROID_SRC/out/host/linux-x86/bin/traceview test.trace 此時可看到各個函數被調用的次數CPU佔用率等信息 e)使用android自帶工具分析生成調用關系類圖 $ apt-get install graphviz# 安裝圖片相關軟體 $ANDROID_SRC/out/host/linux-x86/bin/dmtracemp -g test.png test.trace 此時目錄下生成類圖test.png 3)注意 trace文件生成與libdvm模塊DEBUG版本相沖突,所以此方法只適用於對非DEBUG版本模擬器的調試,否則在分析trace文件時會報錯 2.HProf (Heap Profile) 1)功能: 用於java層面的內存分析,顯示詳細的內存佔用信息,指出可疑的內存泄漏對象 2)方法: a)在代碼中加入mp動作 import android.os.Debug; import java.io.IOException; …… try { android.os.Debug.mphprofData(「/data/tmp/input.hprof」); // 先建/data/tmp目錄 } catch (IOException ioe) { } b)把hprof文件復制到PC端 $ adb pull /data/tmp/input.hprof ./ c)使用命令hprof-conv把hprof轉成MAT識別的標準的hprof $ $ANDROID_SRC/out/host/linux-x86/bin/hprof-conv input.hprof output.hprof d)使用MAT工具看hprof信息 下載MAT工具:/mat/downloads.php 用工具打開output.hprof 3)注意:此工具只能顯示java層面的,而不能顯示C層的內存佔用信息 3.SamplingProfile (android 2.0上版本使用) 1)功能 每隔N毫秒對當前正在運行的函數取樣,並輸出到log中 2)在代碼中加入取樣設定 import dalvik.system.SamplingProfiler …… SamplingProfile sp = SamplingProfiler.getInstance(); sp.start(n);// n為設定每秒采樣次數 sp.logSnapshot(sp.snapshot()); …… sp.shutDown(); 它會啟一個線程監測,在logcat中列印信息 4.用發系統信號的方式取當前堆棧情況和內存信息 1)原理 dalvik虛擬機對SIGQUIT和SIGUSR1信號進行處理(dalvik/vm/SignalCatcher.c),分別完成取當前堆棧和取當前內存情況的功能 2)用法 a)$ chmod 777 /data/anr -R# 把anr目錄許可權設為可寫 $ rm /data/anr/traces.txt# 刪除之前的trace信息 $ ps # 找到進程號 $ kill -3 進程號 # 發送SIGQUIT信號給該進程,此時生成trace信息 $ cat /data/anr/traces.txt 功能實現:遍歷thread list(dalvik/vm/Thread.c:dvmDumpAllThreadEx()),並列印當前函數調用關系(dalvik/vm/interp/Stack.c:mpFrames()) b)$ chmod 777 /data/misc -R $ ps # 找到進程號 $ kill -10 進程號 # 發送SIGQUIT信事信號給該進程,此時生成hprof信息 $ ls /data/misc/*.hprof 此時生成hprf文件,如何使用此文件,見第二部分(HProf) 注意:hprof文件都很大,注意用完馬上刪除,以免占滿存儲器 5.logcat及原理 1)android.util.Log利用println的標准java輸出詞句,並加前綴I/V/D…. 2)dalvik利用管道加線程的方式,先利用p2把stdout和stderr重定向到管理中(vm/StdioConverter.c:dvmstdioConverterStartup),然後再啟動一個線程從管道另一端讀出內容(dalvik/vm/StdioConverter.c:stdioconverterThreadSt art()),使用LOG公共工具(system/core/liblog/logd_write.c: __android_log_print())輸出到/dev/log/*中去 3)logcat通過加不同參數看/dev/log/下的不同輸入信息 # logcat -b main顯示主緩沖區中的信息 # logcat -b radio顯示無線緩沖區中的信息 # logcat -b events顯示事件緩沖區中的信息 6.jdwp(java debug wire protocol)及原理 1)虛擬機(設備端)在啟動時載入了Agent JDWP 從而具備了調試功能。在調試器端(PC端)通過JDWP協議與設備連接,通過發送命令來獲取的狀態和控制Java程序的執行。JDWP 是通過命令(command)和回復(reply)進行通信的。 2)JDK 中調試工具 jdb 就是一個調試器,DDMS也提供調試器與設備相連。 3)dalvik為JDWP提供了兩種連接方式:tcp方式和adb方式,tcp方式可以手工指定埠,adb方式自動設定為8700埠,通常使用DDMS調試就是通過adb方式 7.monkey 1)monkey是一個android自帶的命令行工具。它向系統發送偽隨機的用戶事件流,實現對正在開發的應用程序進行壓力測試。 2)方法 在設備端打開setting界面 $ adb shell # monkey -p com.android.settings -v 500 此時可以看到界面不斷被切換 8.其它小工具 具體見android.os.Debug中提供的工具 1)取毫微秒級的時間,用於計算時間 threadCpuTimeNanos() 2)統計兩點間的內存分配情況 startAllocCounting() stopAllocCounting() getGlobalAllocCount() get….. 3)列印當前已load的class getLoadedClassCount() printLoadedClasses()它需要打開NDEBUG功能才能打開system/core/中Log功能 9.列印debug信息 $ adb bugreport

2. Android內存優化三:內存泄漏檢測與監控

Android內存優化一:java垃圾回收機制
Android內存優化二:內存泄漏
Android內存優化三:內存泄漏檢測與監控
Android內存優化四:OOM
Android內存優化五:Bitmap優化

Memory Profiler 是 Profiler 中的其中一個版塊,Profiler 是 Android Studio 為我們提供的性能分析工具,使用 Profiler 能分析應用的 CPU、內存、網路以及電量的使用情況。

進入了 Memory Profiler 界面。

點擊 Record 按鈕後,Profiler 會為我們記錄一段時間內的內存分配情況。

在內存分配面板中,通過拖動時間線來查看一段時間內的內存分配情況

通過搜索類或者報名的方式查看對象的使用情況

使用Memory Profiler 分析內存可以查看官網: 使用內存性能分析器查看應用的內存使用情況

對於內存泄漏問題,Memory Profiler 只能提供一個簡單的分析,不能夠確認具體發生問題的地方。

而 MAT 就可以幫我們做到這一點,它是一款功能強大的 Java 堆內存分析工具,可以用於查找內存泄漏以及查看內存消耗情況。

as 生成hprof文件無法被mat識別,需要進行轉換

使用hprof-conv進行轉換,hprof-conv位於sdkplatform-tools

ps:as導出hprof前最好先gc幾次,可排除一些干擾

Histogram 可以列出內存中的對象,對象的個數以及大小; Dominator Tree 可以列出那個線程,以及線程下面的那些對象佔用的空間; Top consumers 通過圖形列出最大的object; Leak Suspects 通過MA自動分析泄漏的原因。

Shallow Heap就是對象本身佔用內存的大小,不包含其引用的對象內存,實際分析中作用不大。常規對象(非數組)的ShallowSize由其成員變數的數量和類型決定。數組的shallow size有數組元素的類型(對象類型、基本類型)和數組長度決定。對象成員都是些引用,真正的內存都在堆上,看起來是一堆原生的byte[], char[], int[],對象本身的內存都很小。

Retained Heap值的計算方式是將Retained Set(當該對象被回收時那些將被GC回收的對象集合)中的所有對象大小疊加。或者說,因為X被釋放,導致其它所有被釋放對象(包括被遞歸釋放的)所佔的heap大小。

Path To GC Roots -> exclude all phantim/weak/soft etc. references:查看這個對象的GC Root,不包含虛、弱引用、軟引用,剩下的就是強引用。從GC上說,除了強引用外,其他的引用在JVM需要的情況下是都可以 被GC掉的,如果一個對象始終無法被GC,就是因為強引用的存在,從而導致在GC的過程中一直得不到回收,因此就內存泄漏了。

List objects -> with incoming references:查看這個對象持有的外部對象引用

List objects -> with outcoming references:查看這個對象被哪些外部對象引用

使用對象查詢語言可以快速定位發生泄漏的Activity及Fragment

使用 MAT 來分析內存問題,效率比較低,為了能迅速發現內存泄漏,Square 公司基於 MAT 開源了 LeakCanary ,LeakCanary 是一個內存泄漏檢測框架。

集成LeakCanary後,可以在桌面看到 LeakCanary 用於分析內存泄漏的應用。

當發生泄漏,會為我們生成一個泄漏信息概覽頁,可以看到泄漏引用鏈的詳情。

LeakCanary 會解析 hprof 文件,並且找出導致 GC 無法回收實例的引用鏈,這也就是泄漏蹤跡(Leak Trace)。

泄漏蹤跡也叫最短強引用路徑,這個路徑是 GC Roots 到實例的路徑。

LeakCanary 存在幾個問題,不同用於線上監控功能

線上監控需要做的,就是解決以上幾個問題。

各大廠都有開發線上監控方案,比如快手的 KOOM ,美團的 Probe ,位元組的 Liko

快手自研OOM解決方案KOOM今日宣布開源

總結一下幾點:

通過無性能損耗的 內存閾值監控 來觸發鏡像採集。將對象是否泄漏的判斷延遲到了解析時

利用系統內核COW( Copy-on-write ,寫時復制)機制,每次mp內存鏡像前先暫停虛擬機,然後fork子進程來執行mp操作,父進程在fork成功後立刻恢復虛擬機運行,整個過程對於父進程來講總耗時只有幾毫秒,對用戶完全沒有影響。

3. 如何使用MAT分析Android應用內存泄露

使用Android Studio,Android Device Monitor 配合Eclipse的MAT(

Memory Analyzer)工具來分析android內存泄露。

1、新建一個Android 測試應用。填寫好應用的名稱,以及保存位置後,直接下一步到最後點擊「Finish」。

4. Android技術分享|Android 中部分內存泄漏示例及解決方案

內存泄漏:

舉例:

請注意以下的例子是虛構的

內存抖動

源自Android文檔中的 Memory churn 一詞,中文翻譯為內存抖動。

指快速頻繁的創建對象從而產生的性能問題。

引用Android文檔原文:

Java內存泄漏的根本原因是 長生命周期 的對象持有 短生命周期 對象的引用就很可能發生內存泄漏。

盡管短生命周期對象已經不再需要,但因為長生命周期依舊持有它的引用,故不能被回收而導致內存泄漏。

靜態集合類引起的內存泄漏


如果僅僅釋放引用本身(tO = null), ArrayList 依然在引用該對象,GC無法回收。

監聽器

在Java應用中,通常會用到很多監聽器,一般通過 addXXXXListener() 實現。但釋放對象時通常會忘記刪除監聽器,從而增加內存泄漏的風險。

各種連接

如資料庫連接、網路連接(Socket)和I/O連接。忘記顯式調用 close() 方法引起的內存泄漏。

內部類和外部模塊的引用

內部類的引用是很容易被遺忘的一種,一旦沒有釋放可能會導致一系列後續對象無法釋放。此外還要小心外部模塊不經意的引用,內部類是否提供相應的操作去除外部引用。

單例模式

由於單例的靜態特性,使其生命周期與應用的生命周期一樣長,一旦使用不恰當極易造成內存泄漏。如果單利持有外部引用,需要注意提供釋放方式,否則當外部對象無法被正常回收時,會進而導致內存泄漏。

集合類泄漏

如集合的使用范圍超過邏輯代碼的范圍,需要格外注意刪除機制是否完善可靠。比如由靜態屬性 static 指向的集合。

單利泄漏

以下為簡單邏輯代碼,只為舉例說明內存泄漏問題,不保證單利模式的可靠性。


AppManager 創建時需要傳入一個 Context ,這個 Context 的生命周期長短至關重要。

1. 如果傳入的是 Application 的 Context ,因為 Application 的生命周期等同於應用的生命周期,所以沒有任何問題。

2. 如果傳入的是 Activity 的 Context ,則需要考慮這個 Activity 是否在整個生命周期都不會被回收了,如果不是,則會造成內存泄漏。

非靜態內部類創建靜態實例造成的內存泄漏


應該將該內部類單獨封裝為一個單例來使用。

匿名內部類/非同步線程


Runnable都使用了匿名內部類,將持有MyActivity的引用。如果任務在Activity銷毀前未完成,將導致Activity的內存無法被回收,從而造成內存泄漏。

解決方法:將Runnable獨立出來或使用靜態內部類,可以避免因持有外部對象導致的內存泄漏。

Handler造成的內存泄漏


Handler屬於TLS(Thread Local Storage)變數,生命周期與Activity是不一致的,容易導致持有的對象無法正確被釋放

當Android應用程序啟動時,該應用程序的主線程會自動創建一個Looper對象和與之關聯的MessageQueue。

當主線程中實例化一個Handler對象後,它就會自動與主線程Looper的MessageQueue關聯起來。所有發送到MessageQueue的Messag都會持有Handler的引用,所以Looper會據此回調Handle的handleMessage()方法來處理消息。只要MessageQueue中有未處理的Message,Looper就會不斷的從中取出並交給Handler處理。

另外,主線程的Looper對象會伴隨該應用程序的整個生命周期。

在Java中,非靜態內部類和匿名類內部類都會潛在持有它們所屬的外部類的引用,但是靜態內部類卻不會。

當該 Activity 被 finish() 掉時,延遲執行任務的 Message 還會繼續存在於主線程中,它持有該 Activity 的 Handler 引用,所以此時 finish() 掉的 Activity 就不會被回收了從而造成內存泄漏(因 Handler 為非靜態內部類,它會持有外部類的引用,在這里就是指 SampleActivity)。


避免不必要的靜態成員變數

對於BroadcastReceiver、ContentObserver、File、Cursor、Stream、Bitmap等資源的使用,應在Activity銷毀前及時關閉或注銷。

不使用WebView對象時,應調用`destroy()`方法銷毀。

5. Android開發中,有哪些好方法可以檢測內存泄露和性能

下面是回答的內容


內存泄露,是Android開發者最頭疼的事。可能一處小小的內存泄露,都可能是毀於千里之堤的蟻穴。怎麼才能檢測內存泄露呢?網上教程非常多,不過很多都是使用Eclipse檢測的, 其實1.3版本以後的Android Studio 檢測內存非常方便, 如果結合上MAT工具,LeakCanary插件,一切就變得so easy了。


熟悉Android Studio界面工欲善其事,必先利其器。


我們接下來先來熟悉下Android Studio的界面

結果

非獨占時間:某函數佔用的CPU時間,包含內部調用其它函數的CPU時間。
獨占時間:某函數佔用CPU時間,但不含內部調用其它函數所佔用的CPU時間。

我們如何判斷可能有問題的方法?

通過方法的調用次數和獨占時間來查看,通常判斷方法是:

如果方法調用次數不多,但每次調用卻需要花費很長的時間的函數,可能會有問題。

如果自身佔用時間不長,但調用卻非常頻繁的函數也可能會有問題。

綜述

上面給大家介紹了若干使用Android Studio檢查程序性能的工具,工具永遠是輔助,不要因為工具耽誤太長時間。如果有問題,歡迎大家糾正。

6. 排查內存泄漏最簡單和直觀的方法

內存泄漏無疑會嚴重影響用戶體驗,一些本應該廢棄的資源和對象無法被釋放,導致手機內存的浪費,app使用的卡頓,那麼如何排查內存泄漏呢?

當然,首先我門有google的官方文檔可以參考:

大部分博客的方法也來自於此。總的來說,就是使用android studio 的monitor memory功能監測app主進程佔用的內存,觸發GC操作,而後觀察內存的佔用情況,如果在使用的過程中內存不斷增加,沒有回落, 很有可能 發生了內存泄漏,這時候就需要導出內存分配的具體詳情進行深入分析了。

但是事實上,通過觀察這個內存曲線的曾場來或者是觀察allocate tracker中的allocate data數值的增長來檢測是否有內存泄漏問題,真的很玄,因為往往內存泄漏發生了,但是GC仍然可以通過回收其他對象的方式騰出空間,導致這個數據的變化基本看不出來,甚至是減小的,所以我覺得這種方式, 就像是讓你用手掌去感知嬰兒的體溫,去檢測確定這個嬰兒有沒有發燒一樣,非常不靠譜不準確。

那麼,重點來了,我的方法,簡單直觀,保准你一學就會!

先說一個terminal指令: 

這條指令是用來查詢這個進程所佔用的內存的具體詳情的,通過這條指令可以看到當前app在手機中佔用的具體的堆內存大小,view的數量, activity的數量 ,等等。如下圖:

其中activity數目是非常關鍵的一個信息,可以幫助我們快速地檢測出內存泄漏。我們可以反復地進入退出需要測試的目標activity,如果在反復進入退出之後,用terminal執行上面的語句查詢當前的內存情況,如果發現activity數量一直在增長,那麼內存泄露一定是發生了!

內存泄漏已經發生,如何定位原因呢?

如下圖,在android studio中開始memory monitor,點擊init GC,反復進入退出發生了內存泄漏的activity,這時候點擊生成內存文件,這之後android studio會自動打開生成的.hprof文件。選中該文件轉化成標準的hrof文件。

用MAT工具打開生成的.hprof文件,點擊如下所示的圖標,可以看到內存中的對象列表。

考慮到大內存的泄漏都是因為Activity被destroy之後卻仍然被其他對象持有而造成的,因此首先解決棘手問題,直接搜索Activity,如下。發現有Activity的實例個數是3,跟實際不符,明顯這個activity導致內存泄漏了,按照如圖的方式找到它的引用,也就是導致內存泄漏的幕後兇手!

可以看到這個例子中的內存泄漏是由一個HandlerThread引發的,那麼找到這個問題的位置,在合適的地方(如ondestroy)將這個handler thread釋放即可。

如下圖所示: 在android studio中打開生成的hprof文件,在右側邊欄會出現的Analyzer Tasks工具,點擊執行圖標,即可出現檢測分析的結果,得到哪些activity被泄漏了,這些被泄漏的activity被誰引用了。

可以看到內存泄漏由AsyncHandler引起,需要在activity生命周期結束的時候進行釋放。

方法2不用安裝MAT工具,更加便捷哦~

 有問題可以留言,謝謝您的閱讀~~

7. 怎麼分析android代碼是否存在內存泄露

1、首先確定是否有內存泄露及哪個程序造成。
1.1、內存泄露已彈出out of memory對話框的情況。
這種情況很簡單,直接看對話框就知道是哪個應用的問題了。然後再分析該應用是否是因為內存泄露造成的
out of memory對話框。
》中介紹的各種方法進行分析,確定是否有內存泄露以及是哪個進程造成的內存泄露。
2、生成hprof文件,用MAT進行分析。

成hprof文件可以在DDMS選中進程點擊窗口左上角的mp hprof
file按鈕來直接生成,也可以通過在程序加代碼中來生成代碼2:voidgenerateHprof(){String
packageName=getApplicationInfo().packageName;
StringhpFilePath=/data/data/+packageName+/input.hprof;try{//Debug.mpHprofData(/sdcard/input.hprof);Debug.
mpHprofData
(hpFilePath);}catch(IOException e) {//TODOAuto-generated catch block
e.printStackTrace();}}建議使用代碼生成hprof,然後使用《
Android內存泄露利器(hprof篇)》中的工具自動提取多個hprof文件,然後用MAT進行比較分析。在MAT導入.hprof文件以後,
MAT會自動解析並生成報告,點擊
Dominator Tree
,並按Package分組,選擇自己所定義的Package類,比較各個類在不同時期的RetainedHeap
,找出可疑類,然後選擇該類,點右鍵,選中
show retained Set項,參看Retained Heap
的詳細信息,進一步找出嫌疑項。
3、在代碼中查找內存泄露。
根據在MAT找到的內存泄露信息,參照《
Android內存泄漏簡介
》進一步在內存中查找內存泄露的原因並解決。
另外如果代碼很簡單,可以直接參照《
Android內存泄漏簡介
》在內存中查找內存泄露的原因並解決。

8. Android內存泄露檢測(二)

依賴庫即可,重點在分析工具和分析方法:

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

分析工具:MAT 、AndroidStudioProfiler 和 自帶分析工具;

這里先看一下Leaking的狀態(YES、NO、UNKNOWN),NO表示沒泄露、YES表示出現泄漏、UNKNOW表示可能泄漏。

具體學習資料: 學習資料

首先了解下Android中最重要的四大內存指標的概念

我們主要使用USS和PSS來衡量進程的內存使用情況

mpsys meminfo命令展示的是系統整體內存情況,內存項按進程進行分類

查看單個進程的內存信息,命令如下

adb shell mpsys meminfo [pid | packageName]

Objects中Views、Activities、AppContexts的異常可以判斷有內存泄露,比如剛退出應用,查看Activites是否為0,如果不為0,則有Activity沒有銷毀。

 具體用法直接參考大佬的資源即可,不贅述。

android studio 中Memory Profile的用法

接入LeakCanary,監控所有Activity和Fragment的釋放,App所有功能跑一遍,觀察是否有抓到內存泄露的地方,分析引用鏈找到並解決問題,如此反復,直到LeakCanary檢查不到內存泄露。

adb shell mpsys meminfo命令查看退出界面後Objects的Views和Activities數目,特別是退出App後數目為否為0。

打開Android Studio Memory Profiler,反復打開關閉頁面多次,點擊GC,如果內存沒有恢復到之前的數值,則可能發生了內存泄露。再點擊Profiler的垃圾桶圖標旁的heap mp按鈕查看當面內存堆棧情況,按包名找到當前測試的Activity,如果存在多份實例,則很可能發生了內存泄露。

閱讀全文

與android測試內存泄露相關的資料

熱點內容
設備部門如何做好伺服器 瀏覽:847
androido下載 瀏覽:476
神奇高量戰法副圖源碼 瀏覽:828
匯編語言設計凱撒密碼加密器 瀏覽:390
主次梁加密是加在哪裡 瀏覽:662
模板匹配演算法matlab 瀏覽:823
外地程序員去北京 瀏覽:22
安卓機換蘋果12如何轉移數據 瀏覽:418
互聯網ntp伺服器地址及埠 瀏覽:613
pdf到word轉換器 瀏覽:267
飛行解壓素材 瀏覽:498
51單片機指令用背嗎 瀏覽:936
unityai演算法 瀏覽:834
我的世界ice伺服器如何打開pvp 瀏覽:975
c語言編程如何做標記 瀏覽:884
python數據分析實戰pdf 瀏覽:985
u盤插入文件夾 瀏覽:918
華為amd雲伺服器 瀏覽:497
漢化編程卡是什麼意思 瀏覽:128
python學習pdf 瀏覽:316