教育行業(yè)A股IPO第一股(股票代碼 003032)

全國咨詢/投訴熱線:400-618-4000

Android培訓實戰(zhàn)教程之應用程序內存優(yōu)化

更新時間:2015年12月28日15時33分 來源:傳智播客Android培訓學院 瀏覽次數:

對于開發(fā)一個應用程序來說,在前期完成主要功能之后,后期有一項非常重要的工作,那就是優(yōu)化應用程序的內存。而內存優(yōu)化的方向主要是兩個,一個是內存溢出,另外一個就是內存泄露。
內存溢出和內存泄露是兩個不同的概念。內存溢出指的是內存不夠用了,內存的使用超過的系統規(guī)定的最大值。而內存泄露指的是由于程序的邏輯錯誤,導致一些沒有用的對象無法被垃圾回收器回收而一直占用著內存。所以內存泄露的堆積可能會造成內存溢出。而內存溢出不一定都是由內存泄露引起的。這兩個概念要搞清楚。  ------------------Android培訓學院

內存溢出:

在安卓的應用程序中,內存溢出主要提要在幾個方面
1、ListView的顯示
         我們在使用ListView的時候,都會給他設置Adapter,如果在Adapter中的getView方法 中,我們沒有復用convertView,就會造成在滑動ListView的時候,會為每一個item都    生成一個View對象,而不管這個item之前是否已經生成過View對象。如果來回滑動的次數太多的話,就會造成View生成的數量太多,最終會造成內存溢出。
         如果ListView中的item是包含圖片的,那么,如果在快速滑動的過程中,我們就去為    item加載圖片,此時非常容易造成內存溢出。因為,在快速滑動的過程中,垃圾回收器還來不及回收內存,而新的item又需要新的內存來顯示圖片。所以,在這種情況下,一般的做法是監(jiān)聽ListView的滾動狀態(tài),當ListView的滾動狀態(tài)為空閑的情況下,里面 的每一個Item才去加載圖片。
2、加載圖片相關
         a、加載多張圖片
                   對于加載多張圖片,我們一般會使用三級緩存來實現圖片的加載。內存緩存、本地緩存、網絡緩存。緩存的目的是為了下一次加載速度更快。所以在內存中保存著一定數量的圖片是有助于下一次圖片顯示的速度。但是,內存中不能保存太多的圖片對象,所以我們使用LRUCache來保存內存中的圖片,并且控制在一定的數量之內。
         b、加載單張圖片
                   這種情況是針對于某一張圖片特別大的情況。如果一張圖片非常非常大,如果50M, 那么,我只要一去加載它,那么我的程序肯定就會掛,根本還沒使用到三級緩存應用程序就受不了了。所以,對于大圖片的顯示需要特殊處理。因為圖片雖然特別大,但是這個圖片所需要顯示的控件有可能是很小的。我們可以先把圖片的寬和高得到,再得到這張圖片所需要顯示的控件的寬高,就可以得到圖片和控件的縮放比例了。最后,根據縮放比例,設置圖片的采樣率,來減小單張圖片的內存占用。
1.   BitmapFactory.Options options = new BitmapFactory.Options();    
2.   //只得到圖片的大小,不去加載圖片的內容
3.   options.inJustDecodeBounds = true;
4.   Bitmap boundBitmap = BitmapFactory.decodeFile(filePath,options);
5.   int imageWidth = boundBitmap.getWidth();
6.   int imageHeight = boundBitmap.getHeight();
7.   //計算inSampleSize的值 此時可以根據控件大小和圖片大小來得到縮放比例  這里先寫成2
8.   options.inSampleSize = 2;//圖片寬高都為原來的二分之一,即圖片為原來的四分之一   
9.   options.inJustDecodeBounds = false;  
10.  Bitmap bitmap = BitmapFactory.decodeFile(filePath,options); 

內存泄露:

內存泄露是因為有些對象已經沒有用了,但是卻無法被垃圾回收器回收內存,導致這一塊內存泄露了。隨著這類問題的堆積,泄露的內存越來越大,可使用的內存越來越小,直到內存溢出。
而垃圾回收器無法回收某一些對象,是因為,這些對象有人引用它了。所以內存泄露的本質就是,生命周期短的對象一直被生命周期長的對象引用,導致生命周期短的對象無法被垃圾回收器回收。
在安卓的應用程序當中,內存泄露主要體現在幾個方面
1、注冊了之后忘了反注冊
       BraodcastReceiver,ContentObserver,FileObserver在Activity onDestory或者某類聲明      周期結束之后一定要unregister掉,否則這個Activity會被system強引用,不會被內存 回收。對于觀察者模式的寫法,在注冊某一些觀察者的時候,要既得在適當的時候,把     對應的觀察者從觀察者列表中移除。否則存儲觀察者的集合列表會不斷的擴大。
2、資源對象沒關閉
   資源性對象比如Cursor,File文件等,在內部的實現機制中都用了一些緩沖,所以在不  使用的時候這些資源對象的時候應該及時關閉它們,這樣,他們的緩沖區(qū)域才能被既時     候回收。它們的緩沖不僅存在于Java虛擬機內,還存在于Java虛擬機外。如果我們僅         僅是把它的引用設置為null,而不關閉它們,往往會造成內存泄露。我們需要在這些對象          不使用的情況下,立即調用close方法,然后再設置為null。
3、activity被集合引用導致activity不能釋放
   一般我們在應用程序中,做一個退出應用程序的功能。當點擊退出按鈕的時候,此時應  該把這個應用中所有activity都finish掉,這樣就可以退出這個應用了。所以,我們需   要在每一個activity中的onCreate方法里,將當前啟動的activity保存在某一個集合列     表里面。這個集合列表可以存在于Application中的一個ArrayList。此時,如果在activity          中的onDestory沒有將當前的activity對象從集合列表中移除的話,那么就會造成activity          雖然退出了,但是這個activity的對象依然無法被系統回收,因為有一個集合一直引用         著這個activity對象。所以一定要記得在onDestory方法中把當前的activity對象從集合         列表中移除。
4、Bitmap對象不在使用時調用recycle()釋放內存 
         Bitmap非常的耗內存。 多使用幾個Bitmap很可能一下子就會超過Java堆的限制。因此,在     用完Bitmap時,要       及時的recycle掉。recycle并不能立即將Bitmap的內存釋放,但是會在垃  圾回收器下一個工作的時機將這個bitmap回收。

解決方案

無論是內存泄露還是內存溢出,最終的后果基本上是一致的,那就是造成應用程序強行關閉。在應用程序的功能開發(fā)完之后,怎么樣才能確定應用程序有沒有內存的問題呢?又怎樣來確定到底是哪一塊代碼出的問題呢?接下來我們就來說說關于內存問題的解決方案。
1、使用monkey工具
         因為有些內存問題藏的比較深,要長期使用才能出現異常。所以可以使用monKey工具  來對我們的應用程序進行壓力測試。
         模擬200000次用戶操作的參考命令: adb shell monkey -s 23 -p cn.itcast.XXX(所測試的   包) --ignore-crashes --ignore-timeouts -v -v -v 200000 > D:\文件名.log
         回車之后,我們所需要測試的應用程序就啟動了,并且還有不斷觸摸事件被促發(fā),程序         生成的log會保存在D目錄下。
2、捕獲OOM異常
         自定義Application并讓它實現UncaughtExceptionHandler 接口,在onCreate方法中讓     自己成為系統的默認異常處理機制。Thread.setDefaultUncaughtExceptionHandler(this);
         這樣子設置之后,如果應用程序出現異常,就會調用Application中的uncaughtException 方法。我們就在這個方法中判斷異常是否為OOM異常。如果是OOM異常,就將內存         快照導到sd卡中去。
        
         這樣子之后,我們就可以在sd卡上找到發(fā)生異常時的內存快照
3、分析內存快照
         使用MAT工具對內存快照文件進行分析。
         在使用MAT工具打開內存快照文件的時候,需要先將文件進行轉換一下。因為MAT只  能識別JAVA的內存快照,而我們安卓的內存快照和JAVA的內存快照有點不太一樣,所        以需要進行轉化。
         例如:
        
         接下來就是使用MAT工具打開轉化過后的內存快照文件了。通過MAT工具可以看出這  個內存快照有幾個對象,對象之間的引用關系是怎樣的。這樣對我們定位內存問題非常     有幫助。
         一般在應用程序開發(fā)的后期會使用這三個步驟來增強應用程序的健壯性。

本文版權歸傳智播客Android培訓學院所有,歡迎轉載,轉載請注明作者出處。謝謝!
作者:傳智播客Android培訓學院
首發(fā):http://oisangadgets.com/android/
0 分享到:
和我們在線交談!