編輯:關於Android編程
內存洩漏問題大約是Android開發者最煩惱的問題之一了,項目中連續遇到幾個內存洩漏問題,這裡簡單總結下檢查分析內存洩漏的一些工具與方法。
大家都知道,java是有垃圾回收機制的,這使得java程序員比C++程序員輕松了許多,存儲申請了,不用心心念念要加一句釋放,java虛擬機會派出一些回收線程兢兢業業不定時地回收那些不再被需要的內存空間(注意回收的不是對象本身,而是對象占據的內存空間)。
Q1:什麼叫不再被需要的內存空間?
**答:**Java沒有指針,全憑引用來和對象進行關聯,通過引用來操作對象。如果一個對象沒有與任何引用關聯,那麼這個對象也就不太可能被使用到了,回收器便是把這些“無任何引用的對象”作為目標,回收了它們占據的內存空間。
Q2:如何分辨為對象無引用?
**答:**2種方法
引用計數法
直接計數,簡單高效,Python便是采用該方法。但是如果出現 兩個對象相互引用,即使它們都無法被外界訪問到,計數器不為0它們也始終不會被回收。為了解決該問題,java采用的是b方法。
可達性分析法
這個方法設置了一系列的“GC Roots”對象作為索引起點,如果一個對象 與起點對象之間均無可達路徑,那麼這個不可達的對象就會成為回收對象。這種方法處理 兩個對象相互引用的問題,如果兩個對象均沒有外部引用,會被判斷為不可達對象進而被回收(如下圖)。
Q3:有了回收機制,放心大膽用不會有內存洩漏?
答:答案當然是No!
雖然垃圾回收器會幫我們干掉大部分無用的內存空間,但是對於還保持著引用,但邏輯上已經不會再用到的對象,垃圾回收器不會回收它們。這些對象積累在內存中,直到程序結束,就是我們所說的“內存洩漏”。
當然了,用戶對單次的內存洩漏並沒有什麼感知,但當洩漏積累到內存都被消耗完,就會導致卡頓,崩潰。
內存洩漏不可小視,在Android開發中,比如說一個Activity頁面會占用許多資源開銷,如果頁面發生洩漏,關閉以後頁面沒有能被系統回收,對應用程序的傷害是很大的。
Q1:在Android開發測試中一般如何發現內存洩漏的發生呢?
答:
方法1:反復操作觀察內存變化
內存洩漏常見變現為程序使用時間越長,內存占用越多。那我們通過反復操作應用,比如反復點開/關閉頁面,觀察內存變化狀況是否一點點上漲,可以粗略地判斷是否有內存洩漏
1.通過 DDMS 中的 heap 工具,可以查看應用內存的使用情況
2.Android studio也可以方便查看<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjwvcD4NCjxwPjxpbWcgYWx0PQ=="" src="/uploadfile/Collfiles/20160913/20160913092202790.jpg" title="\" />
方法2:通過代碼檢測Activity洩漏
基本思路:
1)debug版本可以起一個長期工作的線程LeakThread在後台專門做洩漏檢測
2)向Application注冊一個 頁面生命周期 的監聽:application.registerActivityLifecycleCallbacks
3)在監聽類中對 onActivityDestoryed(Activity activity) 的事件回調做處理:
如果一個Activity走到onDestroy,那麼這個Activity對象就是需要被回收的目標。
我們聲明一個檢測對象的弱引用ref = new WeakReference(activity)。
PS:與強引用和軟引用相比,弱引用不會被回收器當做一個“有效”的引用,不會影響其引用對象的釋放。實際上,垃圾回收器會毫不猶豫地回收只有弱引用的對象~
4)在 LeakThread中我們每隔一段時間檢測一下ref.get() 是否為空,為空說明activity已被釋放。不為空可以手動觸一次發gc;如果超過一段時間,比如50s,頁面對象還未被清理,我們可以推斷內存洩漏的發生.
5)當內存洩漏發生時,提示給開發者,並自動dump出.prof文件。
因為代碼檢測不是這裡的重點,代碼就不貼了,只記思路。
發現可能出現內存洩漏時,我們需要對.prof文件進行分析,方能快速定位到是哪個倒霉家伙導致了內存洩漏
打開DDMS ,Eclipse 可以切到DDMS視圖,Android studio可以從Tools-Android-Android device monitor進入DDMS
找到app的進程,在進程上方點擊“update heap”按鈕,可以先主動出發一次GC,待內存占用數據稍微穩定下來後 點擊“Dump HProf File”,便可以導出.prof文件
Android studio可以直接打開prof文件。點開Analyzer Tasks的面板,點擊右上角的開始按鈕。
分析完成後,發生內存洩漏的頁面對象會出現在Analysis Results面板-Leak Activityes的目錄下。
如圖,原來洩漏發生是LoadingRoomActivity的鍋!
在官網可以下載到它:
http://www.eclipse.org/mat/downloads.php
雖然MAT不會准確告訴你你的代碼哪洩漏了,但是它會給你發現哪洩露的數據和線索。
在MAT中打開.prof頁面,你可能會遇到一點小挫折:
如上圖,可能會彈出 ‘Parsing heap dump from xxx has encountered a proplem’ 的錯誤彈窗
這是因為文件版本和編輯器能支持的版本有沖突的原因。
解決方案如下:
Sdk安裝目錄下platform-tools裡有一個hprof-conv工具可以解決該問題。在cmd控制台執行:
hprof-conv input.hprof output.hprof
重新再MAT打開output.hprof 就可以打開了~
值得一提的是,如果你dump出的文件太大的話,也有可能發現打不開的現象,這時候,打開安裝MAT目錄下的MemoryAnalyzer.ini 把-XmX改大些重啟即可。但是也不要改得比你機器的可用內存還大,不能太貪心哈哈~
3.3.2 打開.phrof文件後的分析
通過MAT打開.phrof文件後,會彈出Overview 和 Leak Suspects 2個標簽頁。
Leak Suspects標簽頁可見如下圖:
Leak Suspects視圖展示了app內存占用的比例,淺色是空閒的內存,其他是內存占用的空間。每塊內存對應的問題也都列在下面。點開每個Problem Suspect下的details,可以看到有哪些類的實例占用了內存和占用大小等信息~
此時我們已經有了懷疑的目標,為了更清晰地查看,我們可以回到Overview頁面,打開Histogram頁面:
在打開的Histogram標簽頁中,我們填入檢測對象,在列出的匹配項中過濾掉對象的非強引用。
到這裡我們就可以看到,是哪個壞蛋hold住了你的對象了。MAT能夠給到的支持也就到這裡,接下來,還是需要你根據這些線索到代碼中尋找判別和修正了~“
上一篇文章Android 中的 Service 全面總結詳解【下】 介紹了Service的一些知識以及本地Service的使用,如果對Service還不太了解的建議先看下
前言Android 開發中,我們經常需要實現圖片的圓形/圓角的效果,我們可以使用兩種方式來實現這樣的效果。一種是使用Xfermode,另一種是BitmapShader來實
Android:使用AppCompatAutoCompleteTextView:我們先看看實現的效果吧,也就是我們俗話說的自動提示功能。這裡我實現了點擊AppCompat
handler是什麼? handler是android給我們提供用來更新UI的一套機制,也是一套消息處理的機制,我們可以發送消息,也可以通過他處理消息。 為什麼要用han