Android异常与性能优化相关问题及解决办法
目錄
- ANR異常問題及解決方式
- OOM異常問題及解決方式
- BitMap相關問題
- UI卡頓問題
- 內存泄露問題及解決方式
- 內存管理
- 冷啟動優化問題
- 其他優化介紹
ANR異常問題及解決方式
什么是ANR
ANR全名Application Not Responding, 也就是”應用無響應”. 當操作在一段時間內系統無法處理時, 系統層面會彈出上圖那樣的ANR對話框.
造成ANR的主要原因
在Android里, App的響應能力是由Activity Manager和Window Manager系統服務來監控的. 通常在如下兩種情況下會彈出ANR對話框:
- 5s內無法響應用戶輸入事件(例如鍵盤輸入, 觸摸屏幕等).
- BroadcastReceiver在10s內無法結束.
造成以上兩種情況的首要原因就是在主線程(UI線程)里面做了太多的阻塞耗時操作, 例如文件讀寫, 數據庫讀寫, 網絡查詢等等.
那么Android中哪些操作是在主線程尼?
- Activity的所有生命周期都是執行在主線程
- Service默認是執行在主線程
- BroadcastReceiver的onReceiver回調是執行在主線程的
- 沒有使用子線程的looper的Handler的handleMessage,post(Runnnable)是執行在主線程的。
- AsyncTask的回調中除了donInbackground,其他都在主線程中執行。
如何解決ANR
- 使用AsyncTask處理耗時操作
- 使用Thread或者HandlerThread提高優先級
- 使用handler來處理工作線程的耗時操作
- Activity的onCreate和onResume回調中盡量避免耗時的代碼
OOM異常問題及解決方式
什么是OOM?
當前占用的內存加上我們申請的內存資源超過了Dalvik虛擬機的最大內存限制就會拋出的Out of memory 異常。
一些容易混淆的概念
內存溢出:即是OOM
內存抖動:因為短時間內創建大量的對象,然后瞬間釋放,這段時間占有的內存區域,會產生抖動。
內存泄露:產生內存垃圾,無法被GC回收。
如何解決OOM
產生OOM有以下方式:
- 1.數據庫的cursor沒有關閉。
- 2.構造adapter沒有使用緩存contentview。
- 3.調用registerReceiver()后未調用unregisterReceiver().
- 4.未關閉InputStream/OutputStream。
- 5.Bitmap使用后未調用recycle(),控制圖像縮放大小,使用inBitmap屬性,三級緩存
- 6.Context泄漏。
- 7.static關鍵字等。
- 8.避免在onDraw方法里執行對象的創建
- 9.謹慎使用多進程
BitMap相關問題
- 1.recycle
- 2.LRU
- 3.計算inSampleSize,使用縮略圖
- 4.三級緩存
- 5.軟引用
雖然,系統能夠確認Bitmap分配的內存最終會被銷毀,但是由于它占用的內存過多,所以很可能會超過java堆的限制。因此,在用完Bitmap時,要 及時的recycle掉。recycle并不能確定立即就會將Bitmap釋放掉,但是會給虛擬機一個暗示:“該圖片可以釋放了”, 還有就是, 雖然recycle()從源碼上看,調用它應該能立即釋放Bitmap的主要內存,但是測試表明它并沒能立即釋放內存。故我們還需手動設置為NULL這樣 還能大大的加速Bitmap的主要內存的釋放。。
如下:
對于LRU 請移步我的另一篇博客 Android中LruCache案例及實現原理分析
有時候,我們要顯示的區域很小,沒有必要將整個圖片都加載出來,而只需要記載一個縮小過的圖片,這時候可以設置一定的采樣率,那么就可以大大減小占用的內存。如下面的代碼:
/*** Return the sample size.** @param options The options.* @param maxWidth The maximum width.* @param maxHeight The maximum height.* @return the sample size*/private static int calculateInSampleSize(final BitmapFactory.Options options,final int maxWidth,final int maxHeight) {int height = options.outHeight;int width = options.outWidth;int inSampleSize = 1;while ((width >>= 1) >= maxWidth && (height >>= 1) >= maxHeight) {inSampleSize <<= 1;}return inSampleSize;}private static boolean isEmptyBitmap(final Bitmap src) {return src == null || src.getWidth() == 0 || src.getHeight() == 0;}/*** Return the compressed bitmap using sample size.** @param src The source of bitmap.* @param maxWidth The maximum width.* @param maxHeight The maximum height.* @param recycle True to recycle the source of bitmap, false otherwise.* @return the compressed bitmap*/public static Bitmap compressBySampleSize(final Bitmap src,final int maxWidth,final int maxHeight,final boolean recycle) {if (isEmptyBitmap(src)) return null;BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;ByteArrayOutputStream baos = new ByteArrayOutputStream();src.compress(Bitmap.CompressFormat.JPEG, 100, baos);byte[] bytes = baos.toByteArray();BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);options.inJustDecodeBounds = false;if (recycle && !src.isRecycled()) src.recycle();return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); }附上關于BitMap工具類下載地址
巧妙的運用軟引用(SoftRefrence)
有些時候,我們使用Bitmap后沒有保留對它的引用,因此就無法調用Recycle函數。這時候巧妙的運用軟引用,可以使Bitmap在內存快不足時得到有效的釋放。如下例:
通過使用三級緩存請移步我的另一篇博客 Android中三級緩存實現原理及案例分析
UI卡頓問題
UI卡頓原理
不卡頓情況要60幀操作需要在16ms時間完成,如果完成不了,那么就會造成卡頓現象,渲染失敗,還有一種情況是overDraw情況,一般是重疊View,非必要重疊背景
UI卡頓原因分析
1、人為在UI線程中做輕微耗時操作,導致UI線程卡頓
2、布局Layout過于復雜,無法在16ms內存完成渲染
3、同一時間動畫執行的次數過多,導致CPU或GPU負載過重
4、View過度繪制,導致某些像素在同一幀時間內被繪制多次,從而使CPU或GPU負載過重
5、View頻繁的觸發measure、layout,導致measure、layout累計耗時過多及整個View頻繁的重新渲染
6、內存頻繁觸發GC過多,導致暫時阻塞渲染操作
7、冗余資源及邏輯等導致加載和執行緩慢
8、ANR
UI卡頓總結
1、布局優化:不使用太多嵌套,使用weight 代替長和寬的計算,使用Gone代替invisible
2、列表及Adapter優化
3、背景和圖片等內存分配優化
4、避免ANR
內存泄露問題及解決方式
java內存泄露基礎知識
1、java內存的分配策略
寄存器:我們在程序中無法控制
棧:存放基本類型的數據和對象的引用,但對象本身不存放在棧中,而是存放在堆中
堆:存放用new產生的數據
靜態域:存放在對象中用static定義的靜態成員
常量池:存放常量
非RAM(隨機存取存儲器)存儲:硬盤等永久存儲空間
2、java是如何管理內存的
java管理內存實際上就是對象的生成與釋放的管理,對象的生成是在堆中生成的,釋放是靠GC回收機制,前者是程序員控制,后者靠java虛擬機控制,下面是一個案例:
3、java中的內存泄露
內存泄露是指無用對象(不再使用的對象)持續占有內存或無用對象的內存得不到及時釋放,從而造成的內存空間的浪費稱為內存泄露
- 單例引起的內存泄漏
使與應用生命周期一樣長,持有該對象的引用,
內存泄露問題:
public class AppManager{private static AppManager instance;private Context mcontext;private AppManager(){}private AppManager(Context context){mcontext=context;}private static AppManager getInstance(Context context){if(instance==null){instance=new AppManager(context);}return instance;}} public class AppManager{private static AppManager instance;private Context mcontext;private AppManager(){}private AppManager(Context context){mcontext=context.getApplicationContext();//使用Application的context}private static AppManager getInstance(Context context){if(instance==null){instance=new AppManager(context);}return instance;} }- 匿名內部類
非靜態內部類持有外部類的引用,而使用非靜態內部類創建一個靜態實例。正確解決辦法是將該類變為靜態類
- handler
原因:非靜態內部類持有外部類的引用。
handler造成的內存泄漏解決辦法:
private MyHandler mHandler = new MyHandler(this); private TextView mTextView; private static class MyHandler extends Handler{private WeekReference<Context> reference;public MyHandler(Context context){reference=new WeekReference<>(context);}@Overridepublic void handleMessage(Message msg){MainActivity activity=(MainActivity)reference.get();if(activity!=null){activity.mTextview.setText("");}}}- 避免使用static變量
- 資源未關閉造成的內存泄露。
- AsyncTask造成的內存泄露
原因:非靜態內部類持有外部類引用;
解決辦法:
在Activity的onDestory方法中調用AsyncTask的cancel方法。
4、內存優化方法
- 當Service完成任務后,盡量停止它;
- 在UI不可見的時候,釋放掉一些只有UI使用的資源;
- 在系統內存緊張的時候,盡可能多的釋放掉一些非重要的資源;
- 避免濫用BitMap導致的內存浪費
- 使用針對內存優化過的數據容器 SpareArray代替HashMap 枚舉類型常量是一般常量類型占用內存的兩倍
- 避免使用依賴注入的框架
- 使用ZIP對齊的APK
- 使用多進程,比如通過開啟進程 解決開啟定位,開啟推送,開啟webview加載url
冷啟動優化
冷啟動的定義及與熱啟動的區別
冷啟動:就是在啟動應用前,系統中沒有該應用的任何進程信息。會初始化Application類
熱啟動:用戶使用返回鍵退出應用,然后馬上又重新啟動應用。不會初始化Application類
冷啟動的時間計算:
這個時間從應用啟動(創建進程)開始計算,到完成視圖的第一次繪制(即Activity內容對用戶可見)為止。
冷啟動流程:
1、Zygote進程中fork創建出一個新的進程,
2、創建和初始化Application類、創建MainActivity類,inflate布局;
3、當onCreate/onStart/onResume方法走完,contentView的measure/layout/draw顯示在桌面上
冷啟動流程-總結:
Application的構造方法–>attachBaseContext()—>onCreate()–>Activity的構造方法–>onCreate()–>配置主題中背景等屬性–>onStart()–>onResume()–>測量布局繪制顯示在桌面上。
如何對冷啟動的時間進行優化
1、減少onCreate()方法的工作量
2、不讓Application參與業務的操作
3、不要在Application進行耗時操作
4、不要以靜態變量的方式在Application中保存數據
5、布局/mainThread
其他優化:
- android不要靜態變量存儲數據
1、靜態變量等數據由于進程已經被殺死而被初始化
2、使用其他數據傳輸方式:文件/sp/contentProvider
- 有關Sharepreference問題
1、不能跨進程同步數據讀寫操作
2、存儲Sharepreference的文件過大問題,可能引起ui卡頓,
- 內存對象序列化
1、實現Serializeble接口
2、Parcelable (不適用磁盤數據序列化)
總結:Serializeble是java的序列化方式,Parcelable是Android特有的序列化方式,在使用內存的時候,Parcelable比Serializable性能高
Serializable在序列化的時候會產生大量的臨時變量,從而引起頻繁的GC操作,Parcelable不能使用在要將數據存貯在磁盤的情況
總結
以上是生活随笔為你收集整理的Android异常与性能优化相关问题及解决办法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cent OS7
- 下一篇: 在Android手机上将Minecraf