關于android的內存泄露

內存泄漏:進程中某些對象已經沒有使用價值了,但是它們卻可以直接或間接地引用到,導致無法被GC回收。無用的對象占據著內存空間,使得實際可使用內存變小,從而導致內存泄漏了。
內存溢出(OOM):程序在申請內存時,沒有足夠的內存空間供其使用;內存泄漏是導致內存溢出的主要原因之一;
內存泄露的原因主要就是該關閉的資源對象沒有即使釋放;

1.單例造成的內存泄露
單例的特點是其生命周期與application保持一致
大概大多數的單例都是像這么寫的吧
<code>
public class MyTest {
public static MyTest mTest;
private Context mContext;
private MyTest (Context context) {
mContext = context;
}
public static synchronized Test getInstance(Context context) {
if (mTest == null) {
mTest = new MyTest(context);
}
return mTest;
}
}
</code>
①如果傳入的是 Activity 的 Context,當這個 Context 所對應的 Activity 退出時,由于該 Context 的引用被單例對象所持有,其生命周期等于整個應用程序的生命周期,所以當前 Activity 退出時它的內存并不會被回收,從而導致了內存泄露;
②當我們傳入的是Application的Context的時候,單例的生命周期就和Application的一樣長,因為Application的生命周期是貫穿整個程序的,所以MyTest類持有它的引用,也不會造成內存泄露問題。
所以當我們能用Application Context代替的,盡量用Application Context。
2.Bitmap使用不當
Bitmap是一個極容易消耗內存的對象,用完之后要及時回收;
當我們展示圖片區域很小的時候,需要對圖片進行壓縮及降低像素或者加載縮略圖等;
運用Glide加載圖片的時候,ImageView的scaleType設置不當會導致OOM,當設置為我們fitXY時,Glide不會進行縮放,會以全分辨率加載,所以盡量不要設置為fitXY。
3.Handler造成的內存泄漏
非static的handler會持有activity的引用,而如果handler沒有處理完成工作的時候,我們調用finish,則activity不能釋放,這個時候就會出現內存泄漏。
平常我用handler是這樣使用的:
<code>
public class MainActivity extends AppCompatActivity {
...
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
}
};
}
</code>
但是這樣會造成內存泄漏,在Java中在內部創建對象之后會隱式的持有外部對象,也就是說new Handler()之后Handler對象對Activity就有了一個持有,那么此時finish掉Activity的話是沒辦法回收的。這就造成了內存泄漏。
正確使用handler的姿勢應該是這樣的:
<code>
static class MyHandler extends Handler {
private final WeakReference<Test> mActivity;
TestHandler(Test activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
final Test activity = mActivity.get();
if (activity == null || activity.isFinishing()) {
removeCallbacksAndMessages(null);
return;
}
}
}
</code>
4.匿名內部類造成的內存泄露
<code>
public class TestActivity extends Activity {
...
MyRunnable re1 = new MyRunable();
Runnable re2 = new Runnable() {
@Override
public void run() {
...
}
};
}
</code>
其中re2是匿名內部類,ref2的實現對象里面有個引用,這個引用指向TestActivity ,當前的TestActivity 實例會被re2持有,如果將這個引用再傳入一個異步線程,此線程和此Acitivity生命周期不一致的時候,就造成了Activity的泄露。
5.資源性對象未關閉
File,Cursor,Stream,File,Cursor,Stream,BraodcastReceiver,ContentObserver,Bitmap等資源的使用,應該在Activity銷毀時及時關閉或者注銷,否則這些資源將不會被回收,造成內存泄漏。
6.Webview造成的內存泄露
在重復打開有WebView的頁面時,你會發現,應用的內存會不斷升高,銷毀了之后也不會降下來,這樣就出現了內存泄漏了;
使用Webview之后要activity的onDestroy方法中調用webView.removeAllViews()和webView.destroy();new WebView的時候需要傳入ApplicationContext,如果傳入Activity的Context的話,對內存的引用會一直被保持著;
7.靜態變量造成的內存泄露
在 Activity 類中定義一個 static 變量,并將其指向一個運行中的 Activity 實例。如果在 Activity 的生命周期結束之前,沒有清除這個引用,那它就會泄漏。由于 Activity 的類對象是靜態的,一旦加載,就會在 APP 運行時一直常駐內存,如果類對象不卸載,其靜態成員就不會被垃圾回收,應該盡量避免static成員變量引用資源耗費過多的實例;
Android的內存優化的建議:
1 對不用的對象顯示置NULL;
2.使用更加輕量的數據結構;
3內存對象的重復利用,一些數據進行緩存;
4 注冊監聽及時注銷;
5 優化布局,減少嵌套層次;
6 Listview的優化ContentView獲取緩存的view,使用ViewHolder模。建議用recyclerview代替listview;
7 復用系統自帶的資源,如顏色,圖片,簡單的布局,樣式,接口,動畫等;

  • ━━━━━━神獸出沒━━━━━━
  • ┏┓   ┏┓
  • ┏┛┻━━━┛┻┓
  • ┃       ┃
  • ┃   ━   ┃
  • ┃ ┳┛ ┗┳ ┃
  • ┃       ┃
  • ┃   ┻   ┃
  • ┃       ┃
  • ┗━┓   ┏━┛
  • ┃   ┃
  • ┃   ┃
  • ┃   ┗━━━┓
  • ┃       ┣┓
  • ┃       ┏┛
  • ┗┓┓┏━┳┓┏┛
  • ┃┫┫ ┃┫┫
  • ┗┻┛ ┗┻┛
    *━━━━━━━━━━━━━━━━
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容