今天在測一個新項目,報了一個錯誤:
java.lang.OutOfMemoryError,
Failed to allocate a 2822652 byte allocation with 284176 free bytes and 277KB until OOM
機型跟參數
HMNOTE2_V8.5.2.0
其實這個異常,只會在加載大量圖片,數據的時候出現。或者自己寫了處理不當的方法。
而我內存溢出的問題是因為:Handler內存泄露
原因是:我在延時處理一個事件用了Handler(即啟動頁延時2分鐘進入App),但是acitivity關閉后這個handler還在執行。
Handler 的生命周期與Activity 不一致:
當Android應用啟動的時候,會先創建一個UI主線程的Looper對象,Looper實現了一個簡單的消息隊列,一個一個的處理里面的Message對象。主線程Looper對象在整個應用生命周期中存在。
當在主線程中初始化Handler時,該Handler和Looper的消息隊列關聯(沒有關聯會報錯的)。發送到消息隊列的Message會引用發送該消息的Handler對象,這樣系統可以調用 Handler#handleMessage(Message) 來分發處理該消息。
handler 引用 Activity 阻止了GC對Acivity的回收
在Java中,非靜態(匿名)內部類會默認隱性引用外部類對象。而靜態內部類不會引用外部類對象。
如果外部類是Activity,則會引起Activity泄露 。
當Activity finish后,延時消息會繼續存在主線程消息隊列中1分鐘,然后處理消息。而該消息引用了Activity的Handler對象,然后這個Handler又引用了這個Activity。這些引用對象會保持到該消息被處理完,這樣就導致該Activity對象無法被回收,從而導致了上面說的 Activity泄露。
解決辦法如下:
private class MyHandler extends Handler {
private WeakReference<HandlerActivity> mActivity;
public MyHandler(HandlerActivity activity) {
mActivity = new WeakReference<HandlerActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
if (mActivity.get() == null) {
return;
}
mActivity.get().todo();
}
}
@Override
public void onDestroy() {
if(mHandler!=null){
mHandler.removeCallbacksAndMessages(null);
}
}
//以下是調用的地方
mHandler = new MyHandler(HandlerActivity.this);
mHandler.sendMessageDelayed(Message.obtain(), 1000);
另外這是網上可能解決辦法:
1、圖片建議都放在mipmap目錄下。
2、申請更多的空間。
但并不是所有項目都應該使用這樣的方法去解決OutOfMemoryError問題,如果是大圖片和視頻應用可以使用android:largeHeap="true";
android:hardwareAccelerated="false",
android:largeHeap="true"
Android提供了在以下各級別上啟用或禁止硬加速的能力:
- Application
- Activity
- Window
- View
如下
//清單文件
<applicationandroid:hardwareAccelerated="true">
<activity... />
<activityandroid:hardwareAccelerated="false" />
</application>
//動態代碼
myView.setLayerType(View.LAYER_TYPE_SOFTWARE,null);//禁止個別的View的硬加速
//檢查應用是否被硬加速
View.isHardwareAccelerated():如果View附加到一個硬加速的window上就返回true.
Canvas.isHardwareAccelerated():如果Canvas被硬加速了就返回true.
3、 避免在 activity 或 fragment 之外傳遞 Context 對象。
4、 永遠永遠不要創建靜態的 Context 或 View 對象,或者將二者存儲于靜態變量中。這是內存泄露的首要標志。
private static TextView textView;
private static Context context;