android手機給應用分配的內存一般是8兆左右,若是處理內存處理不當很容易形成OutOfMemoryError,咱們的產品出現最多的錯誤也是OutOfMemoryError的異常,
在解決這個異常時在網上發現不少關於OutOfMemoryError的緣由的介紹。
OutOfMemoryError主要由如下幾種狀況形成:
1.數據庫的cursor沒有關閉。
操做Sqlite數據庫時,Cursor是數據庫表中每一行的集合,Cursor提供了不少方法,能夠很方便的讀取數據庫中的值,
能夠根據索引,列名等獲取數據庫中的值,經過遊標的方式能夠調用moveToNext()移到下一行
當咱們操做完數據庫後,必定要記得調用Cursor對象的close()來關閉遊標,釋放資源。
2.構造adapter沒有使用緩存contentview。
在繼承BaseAdapter時會讓咱們重寫getView(int position, View convertView, ViewGroup parent)方法,
第二個參數convertView就是咱們要用到的重用的對象 html
這裏只講使用方法,具體性能測試文章請見:
ListView中getView的原理+如何在ListView中放置多個item
http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html
Android開發之ListView適配器(Adapter)優化
http://shinfocom.iteye.com/blog/1231511
3.調用registerReceiver()後未調用unregisterReceiver().
廣播接收者(BroadcastReceiver)常常在應用中用到,能夠在多線程任務完成後發送廣播通知UI更新,也能夠接收系統廣播實現一些功能
能夠經過代碼的方式註冊:
IntentFilter postFilter = new IntentFilter();
postFilter.addAction(getPackageName() + ".background.job");
this.registerReceiver(receiver, postFilter);
當咱們Activity中使用了registerReceiver()方法註冊了BroadcastReceiver,必定要在Activity的生命週期內調用unregisterReceiver()方法取消註冊
也就是說registerReceiver()和unregisterReceiver()方法必定要成對出現,一般咱們能夠重寫Activity的onDestory()方法: android
4.未關閉InputStream/OutputStream。
這個就很少說了,咱們操做完輸入輸出流都要關閉流
5.Bitmap使用後未調用recycle()。
圖片處理很差是形成內存溢出的又一個頭號緣由,(在咱們的產品中也有體現),
當咱們處理完圖片以後能夠經過調用recycle()方法來回收圖片對象
數據庫
除此以外:
直接使用ImageView顯示bitmap會佔用較多資源,特別是圖片較大的時候,可能致使崩潰。
使用BitmapFactory.Options設置inSampleSize, 這樣作能夠減小對系統資源的要求。
屬性值inSampleSize表示縮略圖大小爲原始圖片大小的幾分之一,即若是這個值爲2,則取出的縮略圖的寬和高都是原始圖片的1/2,圖片大小就爲原始大小的1/4。
BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options();
bitmapFactoryOptions.inJustDecodeBounds = true;
bitmapFactoryOptions.inSampleSize = 2;
// 這裏必定要將其設置回false,由於以前咱們將其設置成了true
// 設置inJustDecodeBounds爲true後,decodeFile並不分配空間,即,BitmapFactory解碼出來的Bitmap爲Null,但可計算出原始圖片的長度和寬度
options.inJustDecodeBounds = false;
Bitmap bmp = BitmapFactory.decodeFile(sourceBitmap, options);
6.Context泄漏。
這是一個很隱晦的OutOfMemoryError的狀況。先看一個Android官網提供的例子: 緩存
這段代碼效率很快,但同時又是極其錯誤的;
在第一次屏幕方向切換時它泄露了一開始建立的Activity。當一個Drawable附加到一個 View上時,
View會將其做爲一個callback設定到Drawable上。上述的代碼片斷,意味着Drawable擁有一個TextView的引用,
而TextView又擁有Activity(Context類型)的引用,換句話說,Drawable擁有了更多的對象引用。即便Activity被 銷燬,內存仍然不會被釋放。
另外,對Context的引用超過它自己的生命週期,也會致使Context泄漏。因此儘可能使用Application這種Context類型。
這種Context擁有和應用程序同樣長的生命週期,而且不依賴Activity的生命週期。若是你打算保存一個長時間的對象,
而且其須要一個 Context,記得使用Application對象。你能夠經過調用Context.getApplicationContext()或 Activity.getApplication()輕鬆獲得Application對象。
最近遇到一種狀況引發了Context泄漏,就是在Activity銷燬時,裏面有其餘線程沒有停。
總結一下避免Context泄漏應該注意的問題:
1.使用Application這種Context類型。
2.注意對Context的引用不要超過它自己的生命週期。
3.慎重的使用「static」關鍵字。
4.Context裏若是有線程,必定要在onDestroy()裏及時停掉。
7.static關鍵字
當類的成員變量聲明成static後,它是屬於類的而不是屬於對象的,若是咱們將很大的資源對象(Bitmap,context等)聲明成static,那麼這些資源不會隨着對象的回收而回收,
會一直存在,因此在使用static關鍵字定義成員變量的時候要慎重。多線程