一、單例模式引發的內存泄露web
因爲單例模式的靜態特性,使得它的生命週期和咱們的應用同樣長,若是讓單例無限制的持有Activity的強引用就會致使內存泄漏
如錯誤代碼示例:
public class UserInfoBean { private static UserInfoBean userInfoBean; private Context mContext; private UserInfoBean(Context context) { this.mContext = context; } public static UserInfoBean getUserInfoBean(Context context) { if (userInfoBean == null) { synchronized (UserInfoBean.class) { if (userInfoBean == null) { userInfoBean = new UserInfoBean(context); } } } return userInfoBean; } }
正確代碼:數據庫
將 this.mContext = context改爲:this.mContext = context.getApplicationContext();或者代碼中用到的Context可使用本身定義的MyApplication中的MyApplication.getInstance獲取;設計模式
二、Handler引發的內存泄露緩存
Handler引發的內存泄漏在開發中最爲常見的。Handler、Message、MessageQueue都是相互關聯在一塊兒的,若是Handler發送的Message還沒有被處理,那麼該Message以及發送它的Handler對象都會被線程MessageQueue一直持有。性能優化
因爲Handler屬於TLS(Thread Local Storage)變量,生命週期和Activity是不一致的,所以這種實現方式很難保證跟Activity的生命週期一直,因此很容易沒法釋放內存異步
如錯誤代碼:ide
private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mHandler.sendMessageDelayed(Message.obtain(), 60000*5); }
在上面的例子中生命了一個延時5分鐘執行的Message,當該Activity退出的時候,延時任務(Message)還在主線成的MessageQueue中等待,此時的Message持有Handler的強引用,而且因爲Handler是咱們的Activity類的非靜態內部類,因此Handler會持有該Activity的強引用,此時該Activity退出時沒法進行內存回收,形成內存泄漏。oop
解決辦法:將Handler聲明爲靜態內部類,這樣它就不會持有外部類的引用了,Handler的的生命週期就與Activity無關了。不過假若用到Context等外部類的非static對象,仍是應該經過使用Application中與應用同生命週期的Context比較合適性能
正確代碼:優化
private static final class MyHandler extends Handler { private WeakReference<HomeMainActivity> mActivity; public MyHandler(HomeMainActivity mainActivity) { mActivity = new WeakReference<>(mainActivity);
//or
//mActivity=mainActivity.getApplicationContext; } @Override public void handleMessage(Message msg) { super.handleMessage(msg); HomeMainActivity mainActivity = mActivity.get(); if (null != mActivity) { //相關處理 } } }
private final MyHandler mHandler = new MyHandler(this);
mHandler.sendMessageDelayed(Message.obtain(), 60000*5);
雖然咱們結束了Activity的內存泄漏問題,可是通過Handler發送的延時消息還在MessageQueue中,Looper也在等待處理消息,因此咱們要在Activity銷燬的時候處理掉隊列中的消息。
@Override protected void onDestroy() { super.onDestroy(); //傳入null,就表示移除全部Message和Runnable mHandler.removeCallbacksAndMessages(null); }
三、匿名內部類在異步線程中的使用引發的內存泄漏
Android開發常常會繼承實現 Activity 或者 Fragment 或者 View。若是使用了匿名類,而又被異步線程所引用,若是沒有任何措施一樣會致使內存泄漏的:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_inner_bad); Runnable runnable1 = new MyRunnable(); Runnable runnable2 = new Runnable() { @Override public void run() { } }; } private static class MyRunnable implements Runnable{ @Override public void run() { } } }
runnable1 和 runnable2的區別就是,runnable2使用了匿名內部類,咱們看看引用時的引用內存
能夠看到,runnable1是沒有什麼特別的。但runnable2多出了一個MainActivity的引用,如果這個引用再傳入到一個異步線程,此線程在和Activity生命週期不一致的時候,也就形成了Activity的泄露。
四、集合引起的內存泄漏
咱們一般會把一些對象的引用加入到集合容器(好比ArrayList)中,當咱們再也不須要該對象時,並無把它的引用從集合中清理掉,當集合中的內容過於大的時候,而且是static的時候就形成了內存泄漏,全部最好在onDestory清空;
private List<String> nameList; private List<Fragment> list; @Override public void onDestroy() { super.onDestroy(); if (nameList != null){ nameList.clear(); nameList = null; } if (list != null){ list.clear(); list = null; } }
五、Android WebView Memory Leak WebView內存泄漏(查看做者原文)
WebView解析網頁時會申請Native堆內存用於保存頁面元素,當頁面較複雜時會有很大的內存佔用。若是頁面包含圖片,內存佔用會更嚴重。而且打開新頁面時,爲了能快速回退,以前頁面佔用的內存也不會釋放。有時瀏覽十幾個網頁,都會佔用幾百兆的內存。這樣加載網頁較多時,會致使系統不堪重負,最終強制關閉應用,也就是出現應用閃退或重啓。
要使用WebView不形成內存泄漏,首先應該作的就是不能在xml中定義webview節點,而是在須要的時候動態生成。即:能夠在使用WebView的地方放置一個LinearLayout相似ViewGroup的節點,而後在要使用WebView的時候,動態生成即:
WebView mWebView = new WebView(getApplicationgContext()); LinearLayout mll = findViewById(R.id.xxx); mll.addView(mWebView);
而後必定要在onDestroy()方法中顯式的調用
protected void onDestroy() { super.onDestroy(); mWebView.removeAllViews(); mWebView.destroy() }
注意: new WebView(getApplicationgContext()) ;必須傳入ApplicationContext若是傳入Activity的Context的話,對內存的引用會一直被保持着。有人用這個方法解決了當Activity被消除後依然保持引用的問題。可是你會發現,若是你須要在WebView中打開連接或者你打開的頁面帶有flash,得到你的WebView想彈出一個dialog,都會致使從ApplicationContext到ActivityContext的強制類型轉換錯誤,從而致使你應用崩潰。這是由於在加載flash的時候,系統會首先把你的WebView做爲父控件,而後在該控件上繪製flash,他想找一個Activity的Context來繪製他,可是你傳入的是ApplicationContext。後果,你能夠曉得了哈。
參考文章: