內存溢出
抓狂的oom,這個錯誤拋出的原理
內存泄漏
當內存不足時,Android運行時就會觸發GC,GC採用的垃圾標記算法爲根搜索算法。內存泄漏就是指沒有用的對象到GC root是可達的,導致GC無法回收該對象。
內存泄漏的場景
- 非靜態內部類的靜態實例,如
public class InnerActivity extends AppCompatActivity {
private static Object inner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inner);
//
inner=new InnerClass();
}
class InnerClass{}
}
靜態實例inner生命週期與應用程序一樣長,它持有InnerActivity的引用,導致InnerActivity無法被回收。
- 多線程相關的非靜態內部類
public class InnerActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inner);
startAsyncTask();
}
void startAsyncTask(){
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... voids) {
while (true){//耗時任務
}
}
}.execute();
}
}
AsyncTask
的內部匿名類,如果線程不結束,則一直持有Activity的引用。我們可以會使用靜態AsyncTask
或者退出Activity
時結束異步線程。
- Handler內存泄露
Handler
的Message
被存儲在MessageQueue
中, 有些Message
不能立即處理,它們會在MessageQueue
存在很長時間,這會導致Handler無法被回收。如果Handler
是非靜態的,則引用它的Activity
或Service
不能被回收。
解決方案:
- 一個是使用靜態的
Handler
內部類,持有的引用使用弱引用 -
activity
的Destory
方法中,調用handler.removeCallbacksAndMessages(null)
;來移除MessageQueue
中的Message
.
未正確使用Context
對於不是必須使用Activity的Context情況,可以考慮使用Application Context來代替,特別是單例的情況。WebView
在應用中只要使用一次WebView,內存就不會被釋放掉。通常的解決辦法是爲WebView單開一個進程,使用AIDL與應用進行通信。WebView可以根據業務需求在合適的時機進行銷燬。
6.資源對象未關閉
資源對象比如Curso、File等,往往都使用了
內存分析
通過內存分析來發現泄漏點
避免內存抖動
頻煩的內存申請及釋放,會導致短時間的頻煩GC,會嚴重影響程序性能。
解決方法:不要申請大量不必要的對象內存:
1, 不可變對象:String
2, 自動裝箱:Integer, Boolean...
考慮使用對象池並緩存來減少內存抖動
留心enum類型的開銷(一個指向枚舉類型的引用就要佔據4個字節)