1、anr異常面試問題講解
a) 什么是anr?
應用程序無響應對話框
b) 造成anr的原因?
主線程中做了耗時操作
c) android中那些操作是在主線程呢?
activity的所有生命周期回調都是執行在主線程的
Service默認是執行在主線程的
BroadcastReceiver的onReceiver回調是執行在主線程的
沒有使用子線程的Looper的Handler的handlerMessage,post(Runnable)是執行在主線程的
AsyncTask的回調中除了doInBackground,其它都是執行在主線程
d) 如何解決anr
使用AsyncTask處理耗時IO操作
使用Thread或者HandlerThread提高優先級
使用handler來處理工作線程的耗時任務
activity的onCreate和onResume回調中盡量避免耗時的代碼
2、oom異常面試問題講解
a) 什么是oom ?
當前占用的內存加上我們申請的內存資源超過了Dalvik虛擬機的最大內存限制就會拋出的Out of memory異常
b) 一些容易混淆的概念
內存溢出 / 內存抖動 / 內存泄漏
內存溢出:就是oom
內存抖動:短時間內大量對象被創建然后馬上被釋放
內存泄漏:當程序不再使用到的內存時,釋放內存失敗而產生了無用的內存消耗
d) 如何解決oom
1.有關bitmap優化
圖片顯示(比如監聽listview滑動,停止的時候加載大圖)
及時釋放內存
bitmap的夠着方法都是私有的,通過BitmapFactory生成Bitmap到內存中都是通過jni實現的,簡單點說會有倆部分區域,一部分是java區,一部分是C區,但是Bitmap是通過java分配的,不用的時候也是由java的gc機制回收的。對應C區域不能及時回收的,所以這里說的釋放內存就是釋放的c的那塊區域(通過
recycle方法,該方法內部調用了jni的方法)。要是不釋放只能等進程死了以后就會被釋放
圖片壓縮
inBitmap屬性(圖片復用)
捕獲異常
2.其它方法
listview:convertview / lru(三級緩存)
避免在onDraw方法里面執行對象的創建
謹慎使用多進程
3、 bitmap面試問題講解
a) recycle :釋放bitmap內存的時候會釋放所對應的native的內存,但是不會立即釋放,但是調用完就不能使用該bitmap了,是不可逆的。官方不建議主動調用。垃圾回收器主動會清理。
b) LRU:三級緩存,內部是通過map實現的,里面提供了put、get方法來完成緩存的添加和獲取操作。當緩存滿的時候,lru算法會提供trimToSize刪除最久或者使用最少的緩存對象,添加新的緩存對象
c) 計算inSampleSize:
d) 縮略圖
/**
* 獲取縮略圖
* @param imagePath:文件路徑
* @param width:縮略圖寬度
* @param height:縮略圖高度
* @return
*/
public static Bitmap getImageThumbnail(String imagePath, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; //關於inJustDecodeBounds的作用將在下文敘述
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, options);
int h = options.outHeight;//獲取圖片高度
int w = options.outWidth;//獲取圖片寬度
int scaleWidth = w / width; //計算寬度縮放比
int scaleHeight = h / height; //計算高度縮放比
int scale = 1;//初始縮放比
if (scaleWidth < scaleHeight) {//選擇合適的縮放比
scale = scaleWidth;
} else {
scale = scaleHeight;
}
if (scale <= 0) {//判斷縮放比是否符合條件
be = 1;
}
options.inSampleSize = scale;
// 重新讀入圖片,讀取縮放后的bitmap,注意這次要把inJustDecodeBounds 設為 false
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(imagePath, options);
// 利用ThumbnailUtils來創建縮略圖,這里要指定要縮放哪個Bitmap對象
bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height,ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
return bitmap;
}
e) 三級緩存
網絡、本地、內存三級緩存,減少流量的使用
4、 ui卡頓面試問題講解
a) UI卡頓的原理
60fps -> 16ms
overdraw過度繪制
b) 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
c) UI卡頓總結
1.布局優化
2.列表及adapter優化
3.背景和圖片等內存分配優化
4.避免ANR
4、 內存泄漏
a) java內存泄漏基礎知識
1. java內存的分配策略
靜態存儲區(方法區):主要存放靜態數據、全局 static 數據和常量。這塊內存在程序編譯時就已經分配好,並且在程序整個運行期間都存在。
棧區:當方法被執行時,方法體內的局部變量(其中包括基礎數據類型、對象的引用)都在棧上創建,並在方法執行結束時這些局部變量所持有的內存將會自動被釋放。因為棧內存分配運算內置於處理器的指令集中,效率很高,但是分配的內存容量有限。
堆區 : 又稱動態內存分配,通常就是指在程序運行時直接 new 出來的內存,也就是對象的實例。這部分內存在不使用時將會由 Java 垃圾回收器來負責回收。
2. java是如何管理內存的
3. java中的內存泄漏
內存泄漏是指無用對象(不再使用的對象)持續占有內存或無用對象的內存得不到及時釋放,從而造成的內存空間的浪費稱為內存泄漏
b) android內存泄漏
1. 單例
public class AppManager { private Context mContext; private static AppManager instance; private AppManager(Context context){ //有內存泄漏的問題:傳入的是actiivty的context,導致activity沒法釋放 //this.mContext = context; //所以這里應該傳入Application全局的context this.mContext = context.getApplicationContext(); } public static AppManager getInstance(Context context){ if(instance ==null){ instance = new AppManager(context); } return instance; } }
2.匿名內部類
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } //這樣的寫法就會造成內存泄漏 //原因是這樣寫法雖然避免了重復創建,但是非靜態內部類持有外部類的引用, //這時候我們又創建了一個靜態實例TAG的話就會和應用的生命周期一樣長,所以就會使外部的activity沒法釋放 class TestResource{ private static final String TAG = ""; } //正常的寫法,這樣的話就不會持有外部類的引用。 static class TestResource1{ private static final String TAG = ""; } }
3.handler
public class MainActivity extends AppCompatActivity { private TextView mTv; private MyHandler myHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myHandler = new MyHandler(this); } //這樣的寫法會造成內存泄漏 //mHandler是MainActivity的非靜態內部類的實例,它持有外部類的引用,我們知道handler的消息是在一個loop //中不斷的輪詢處理消息,那么當MainActivity退出時,消息隊列中還有沒處理的消息或正在處理的消息,所以會造成內存泄漏 @SuppressLint("HandlerLeak") private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; //這樣寫是正確的寫法 static class MyHandler extends Handler{ //創建一個軟引用 private WeakReference<Context> reference; public MyHandler(Context context){ reference = new WeakReference<Context>(context); } @Override public void handleMessage(Message msg) { MainActivity mainActivity = (MainActivity) reference.get(); if(mainActivity != null){ //TODO------ mainActivity.mTv.setText("11"); } } }
@Override
protected void onDestroy() {
super.onDestroy();
myHandler.removeCallbacksAndMessages(null);
}
}
4.避免使用static靜態變量
如果聲明成靜態變量,那么它的生命周期就會和app的生命周期一樣長,假如你的app是常駐后台的,即使app退到后台,這部分也不會釋放
5.資源未關閉造成的內存泄漏
6.AsyncTask造成的內存泄漏
在onDestory調用cancel()方法
添加弱引用實現
5、內存管理面試問題
a)內存管理機制概述
1.分配機制
2.回收機制
b)Android內存管理機制
1.分配機制
彈性的分配機制,當發現內存不夠用的時候回分配額外的內存。但是額外的內存也不是無限量的。(讓更多的進程存活在系統中)
2.回收機制
前台進程 可見進程 服務進程 后台進程 空進程
c)內存管理機制的特點(目標)
1.更少占用的內存
2.在合適的時候,合理的釋放系統資源
3.在系統內存緊張的情況下,能釋放掉不部分不重要的資源,來為android系統提供可用的內存
4.能夠很合理的在特殊的生命周期中,保存或者還原重要數據,以至於系統能夠正確的重新恢復該應用
d)內存優化方法
1.當service完成任務后,盡量停止它
2.在UI不可見的時候,釋放掉一些只有UI使用的資源
3.在系統資源緊張的時候,盡可能多的釋放掉一些非重要資源
4.避免濫用Bitmap導致的內存浪費
5.使用針對內存優化過的數據容器
6.避免使用依賴注入的框架
7.使用ZIP對齊的APK
8.使用多進程
d)內存溢出VS內存泄漏
6、冷啟動優化面試問題講解
a)什么是冷啟動?
1.冷啟動的定義
冷啟動就是在啟動應用前,系統沒有該應用的任何進程信息
2.冷啟動 / 熱啟動的區別
熱啟動:用戶使用返回鍵退出應用,然后馬上又重新啟動應用
區別:
1). 定義
2). 啟動特點
冷啟動:Application -> MainActivity ->UI的繪制
熱啟動:MainActivity ->UI的繪制
3.冷啟動時間的計算
這個時間值從應用啟動(創建進程)開始計算,到完成視圖的第一次繪制(即Activity內容對用戶可見)為止
b)冷啟動流程
Zygote進程中fork創建一個新的進程
創建和初始化Application類,創建MainActivity類
inflate布局,當onCreate / onStart / onResume方法都走完
contentView的measure / layout /draw 顯示在界面上
c)如何對冷啟動的時間進行優化
1.減少onCreate的工作量
2.不要讓Application參與業務的操作
3.不要在Application進行耗時操作
4.不要以靜態變量的方式在Application中保存數據
5.布局
6.mainThread
d)冷啟動流程-----總結
Application的構造方法-------->attachBaseContext () ---------> onCreate () ----------->Activity的構造方法------------> onCreate () ------------> 配置主題中背景等屬性------------->onStart () ---------> onResume() --------> 測量布局繪制顯示在界面上
7、其他優化面試問題講解
a)android 不用靜態變量存儲數據
1.靜態變量等數據由於進程已經被殺死而被初始化
2.使用其它的數據傳輸方式:文件 / sp / contentProvider
b)有關Sharepreference的安全問題
1.不能跨進程同步數據讀寫
2.存儲Sharepreference的文件過大問題
過大的話會讀取緩慢,造成UI卡頓
讀取頻繁的key和不易變動的key不要放在一起
c)內存對象序列化
序列化:將對象的狀態信息轉化為可以存儲或傳輸的形式的過程
1.實現Serializable接口(會產生大量的臨時變量,頻繁的垃圾回收,這樣會造成UI卡頓,內存抖動,)
2.實現Parcelable接口
總結:1>.Serializable是Java的序列化方式,Parcelable是android特有的序列化方式
2>.在使用內存的時候,Parcelable比Serializable性能高
3>.Serializable序列化的時候會產生大量的臨時變量,從而引起頻繁的GC
4>.Parcelable不能使用在要數據存儲在磁盤上的情況
d)避免在UI線程中做繁重的操作