編輯:關於Android編程
Android開發中避免不了碰到內存洩露問題,這裡先大概講下內存洩露的基本概念:內存洩露官方的解釋是是用動態存儲分配函數動態開辟的空間,在使用完畢後未釋放,結果導致一直占據該內存單元,直到程序結束。它也可以理解為new的新對象用完後,該對象沒有得到回收,造成的無用的對象一直占據著內存,這種無用的隨著操作的次數越多,占據的內存越多,直到內存溢出程序,報錯停止運行。內存溢出問題比起程序直接報錯的問題更難定位,光靠閱讀代碼來分析內存溢出問題工作量也有些大,所以我們就不得不借助工具分析內存溢出問題。這一章節介紹的主要是如何使用內存分析工具MAT。我們用的最多的一般都是Eclipse自帶的DDMS工具,進入DDMS後其界面如下:
這裡先講下該工具的使用步驟:
1.通過USB線連接手機到PC上,android調試終端開啟需要進行內存分析的APP,點擊DDMS選項,進入堆顯示界面。
2.在Devices界面選擇APP的進程名,如圖所示我的APP進程名是com.example.oomtest。
3.接著點擊如上圖所示的左上角綠色按鈕UpdateHeap,用於更新顯示APP的內存堆詳情,點擊後出現上圖右邊的Heap界面,即APP的堆的使用情況。其中Heap Size即APP的堆大小,是可變,至於上限是怎麼設定的可以看下上一章節。Allocated即當前APP分配出去的堆大小,一般進行某個操作後是否內存洩露可以通過查看Allocated是否增大進行簡單的判定,但是不一定准確,但是對於明顯的內存洩露還是可以的,比如加載大圖片並顯示時。
4.上圖右邊的Heap界面,有個Cause GC按鈕是用於觸發你的手機的GC線程進行內存回收。這裡要提下的是一些人在監聽某個界面的堆情況時,進入某個界面退出後根本沒有點擊Cause GC,此時發現退出界面後Allocated大小增大了,以為就是內存洩露了。其實不是的,只是有時GC線程自己還沒掃描到你的APP,此時該APP的堆是還沒有被回收的,所以Allocated的大小比之前的增加了。所以在進行某個操作後,要查看APP的堆情況還要點擊Cause GC,建議多點擊幾次。
5.步驟5的load heap按鈕是用於下載heap內存分析的文件,接著要講的分析工具需要用到該文件。
看到這裡可能有些網友會問了,有些代碼明明是內存洩露了,為什麼Allocted還是顯示正常的,即操作前和操作後,Allocted大小都沒變化。是的,這裡也是使用DDMS查看內存洩露的缺點,一些隱蔽性的內存洩露,用DDMS是看不出來的。所以第二節要講的是通過Memory Analyer工具進行內存洩露分析,這樣會准確很多,也很方便問題的定位。
先講下這個工具不是Eclipse自帶的,所以需要自己下載Memory Analyer Tools(簡稱MAT,也可以作為插件集成到Eclipse中),本人是自己下載Memory Analyer工具。安裝好Memory Analyer工具後,接著講操作步驟:
1.點擊上圖中的步驟5中的load heap按鈕下載堆分析文件,即後綴名為hprof的文件。
2. 由於下載的hprof文件在MAT中無法正常讀入,所以需要sdk中的hprof-conv進行轉換才可以在MAT正常讀入。為了方便文件轉換,接著進入sdk中查看hprof-conv工具放在什麼位置,建議未轉換前的hprof文件跟hprof-conv放在同一目錄下,因為接著在cmd中進行轉換時不用輸入太長的文件路徑。本人這裡的hprof-conv工具的絕對路徑為D:\ProgramFiles\eclipse\Android-sdk-windows-full\platform-tools>hprof-conv,同時也把轉換前的hprof文件也放到這個位置。
3.打開cmd,進入到hprof-conv所在的目錄下,輸入hprof-conv old.hprof new.hprof後按回車鍵,接著在D:\ProgramFiles\eclipse\Android-sdk-windows-full\platform-tools目錄下生成的new.hprof文件,即為MAT可以讀入的hprof文件。注:其中old.hprof為轉換前的文件名,new.hprof為轉換後的文件名,
4.打開MAT,並導入轉換後的hprof文件,操作如下圖右上角所示:
5.導入後的界面如下圖所示,界面上的Problemsupect就是MAT幫你找出來的可能內存洩露的地方,看到這裡你可能會想,這樣很方便啊,MAT都幫你把所有可能內存洩露的地方都找出來了,接著點擊Problem Supect一個一個慢慢看就可以了,其實網上很多貼也是這麼說的。在這裡我想說通過Problem Supect來定位某些內存洩露問題(比如加載大圖片或者加載很多小圖片的情況下)也是一種方法,但是此方法跟Eclipse的Heap來分析內存洩露一樣,也是不准確的。
下面重點介紹下另外一種MAT分析內存洩露的方法。到這裡你可以又會有疑問了什麼樣的內存洩露是上面介紹的兩個方法可能檢測不出來的,這裡也順便說下吧。
(1). Activity的context被生命周期更長的對象(內部類和靜態變量等)占據,導致的內存洩露問題。
(2). Cursor用完沒有colse造成的內存洩露問題。
另外,下面的介紹會用到一些基本概念,這裡先普及下: (1)Shallow Heap是對象本身占據的內存的大小,不包含其引用的對象。對於常規對象(非數組)的Shallow Size由其成員變量的數量和類型來定,而數組的ShallowSize由數組類型和數組長度來決定,它為數組元素大小的總和。(2)Retained Heap為當前對象大小+當前對象可直接或間接引用到的對象的大小總和。(間接引用的含義:A->B->C,C就是間接引用) ,並且排除被GC Roots直接或者間接引用的對象
操作步驟:
(1).步驟1,點擊Overview選項,進入到主界面
(2).步驟2,點擊Histogram選項,進入到Histogram界面,如下圖所示。其中進程名輸入框用於輸入APP的進程名,從而可以查看APP的堆情況。
下面用一個內存洩露例子簡單分析下,方便網友入門。在Activity中定義一個線程內部類,並在線程中長時間休眠,該測試APP的進程名為com.example.oomtest,關鍵代碼如下:
protectedvoid onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); Log.i(TAG, "onCreate"); setContentView(R.layout.activity_second); new TestThread().start(); } publicclass TestThread extends Thread { @Override publicvoid run() { super.run(); try { Thread.sleep(1000 * 60 *1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
進入測試界面並退出該界面操作一次,我們在獲取hropf文件並轉換導入MAT中,打開Histogram界面後,在
從上圖中的Objects列中可以看出當退出測試界面SencondActivity時,它的實例存在。所以可以判定SencondActivity發生了內存洩露,但是使用前面介紹的兩種方法根本就分析不出APP發生了內存洩露。到這裡你可能也會問,知道了SencondActivity發生了內存洩露,那麼要怎麼知道具體哪裡發生了內存洩露呢?這個也簡答,這就是通過Histogram進行分析內存洩露的優勢了,操作步驟如下圖所示:
跟著上圖所示操作,接著出現以下界面,從下圖中可以看出activity實例沒有被回收,這就是前面所說的隱藏性比較強的內存洩漏類型1了,主要原因就是Activity中的線程一直占住了Activity的this造成的內存洩露,所以當該Activity被Destroy時,Activity的實例沒法被GC回收。
現將線程的休眠時間修改為100時,按同樣的操作方法測試,SencondActivity的子線程由於休眠時間比較短,此時當Activity被Destroy時,Activity的this已經被釋放了,所以不會發生內存洩露的情況,其堆內存情況如圖所示:
從列表中可以看出此時SencondACtity的Object(對象)為0,即SencondActivity沒有存在對象,所以用該方法進行內存洩露分析是很准確的,但是同樣的程序通過前面的兩種方法就無法定位出哪裡出問題,甚至檢測不出內存洩露了。這一章就先介紹到這裡吧,下一章節將介紹其他一些隱藏性比較強的內存洩露問題,以便各大網友開發出高質量的APP。
綜述 View的繪制流程可以分為三大步,它們分別是measure,layout和draw過程。measure表示View的測量過程,用於測量View的寬度和高度;lay
最近編程時,發現一個針對HashMap的一個提示:翻譯過來就是:用SparseArray來代替會有更好性能。那我們就來看看源碼中SparseArray到底做了哪些事情:一
篇外話:先來說下今天的日期,今天是2015年02月18日也就是大年三十,大家都在歡歡喜喜的准備過大年,活動也各式各樣,搓麻將、打撲克、放煙花、准備看春晚,而我卻還在敲代碼
先說一下adb命令配置,如果遇到adb不是內部或外部命令,也不是可運行的程序或批量文件。配置下環境變量1、adb不是內部或外部命令,也不是可運行的程序或批量文件。解決辦法