本文據(jù)《Android應用性能最佳實踐優(yōu)化(羅彧成)》總結(jié)而成邮旷。
資源性對象未關(guān)閉
資源性對象(如Cursor累舷、File等)往往都用到緩存,在不使用時壤圃,應及時關(guān)閉它們陵霉,以便它們的內(nèi)存數(shù)據(jù)能夠及時回收。有些資源性對象伍绳,如SQLite Cursor踊挠,如果沒有手動關(guān)閉它,在系統(tǒng)回收它時也會關(guān)閉之冲杀,但這樣的效率太低效床,還是建議不使用時立即手動調(diào)用close()函數(shù),將其關(guān)閉权谁,然后再置為null剩檀。在程序退出時,一定要確保資源性對象已經(jīng)關(guān)閉旺芽。注冊對象未注銷
如果事件注冊后未注銷沪猴,會導致觀察者列表中維持著對對象的引用,阻止垃圾回收采章,這一般發(fā)生在注冊廣播接收器运嗜、注冊觀察者等。類的靜態(tài)變量持有大數(shù)據(jù)對象
靜態(tài)變量長期維持對對象的引用悯舟,阻止垃圾回收担租,如果靜態(tài)變量持有大的數(shù)據(jù)對象,如Bitmap等抵怎,就很容易引起內(nèi)存不足等問題奋救。非靜態(tài)內(nèi)部類的靜態(tài)實例
非靜態(tài)內(nèi)部類會維持一個對外部類實例的引用阱洪,如果非靜態(tài)內(nèi)部類的實例是靜態(tài)的,就會間接長期持有對外部類的引用菠镇,阻止外部類被系統(tǒng)回收冗荸。
為避免這種情況發(fā)生,可以將內(nèi)部類設置為靜態(tài)內(nèi)部類或將內(nèi)部類抽取出來并封裝為一個單例利耍,如果需要使用Context蚌本,在沒有特殊要求的情況下使用Application的Context,如果需要使用Activity的Context隘梨,就在用完之后置空讓GC可以回收程癌,否則還是會內(nèi)存泄漏。Handler臨時性內(nèi)存泄漏
Handler對象通過發(fā)送Message實現(xiàn)線程之間的交互轴猎,Message發(fā)出之后存儲在MessageQueue中嵌莉,有些Message也不是馬上就被處理。在Message中存在一個target捻脖,它是Handler的一個引用锐峭,Message在Queue中存在的時間過長,就會導致Handler無法被回收可婶。如果Handler是非靜態(tài)的沿癞,則會導致Activity或Service不會被回收。
未避免這種內(nèi)存泄漏矛渴,需要做到以下兩個地方:
- 使用一個靜態(tài)Handler內(nèi)部類椎扬,然后對Handler持有的對象使用弱引用,這樣在回收時具温,也可以回收Handler持有的對象蚕涤。
- 在Activity的Destroy或者Stop時,應移除消息隊列中的消息铣猩,避免Looper線程的消息隊列中有待處理的消息需要處理揖铜。
容器中的對象沒清理造成的內(nèi)存泄漏
有時會將一些對象的引用加入集合中,在不需要該對象時剂习,如果沒有把它的引用從集合中清理出去蛮位,這個集合就會越來越大。如果這個集合是static的鳞绕,情況就更嚴重失仁。WebView
Android的WebView不僅存在很大的兼容性問題,不同Android系統(tǒng)版本中的WebView也有較大差異们何。WebView都存在內(nèi)存泄漏的問題萄焦,在應用中只要使用一次WebView,內(nèi)存就不會被釋放掉。通常解決這個問題的方法是為WebView開啟獨立的一個進程拂封,使用AIDL與應用的主線程進行通信茬射,WebView所在的進程可以根據(jù)業(yè)務的需要選擇適合的時機進行銷毀,達到正常釋放內(nèi)存的目的冒签。