關(guān)于android的內(nèi)存泄露

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

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

  • ━━━━━━神獸出沒━━━━━━
  • ┏┓   ┏┓
  • ┏┛┻━━━┛┻┓
  • ┃       ┃
  • ┃   ━   ┃
  • ┃ ┳┛ ┗┳ ┃
  • ┃       ┃
  • ┃   ┻   ┃
  • ┃       ┃
  • ┗━┓   ┏━┛
  • ┃   ┃
  • ┃   ┃
  • ┃   ┗━━━┓
  • ┃       ┣┓
  • ┃       ┏┛
  • ┗┓┓┏━┳┓┏┛
  • ┃┫┫ ┃┫┫
  • ┗┻┛ ┗┻┛
    *━━━━━━━━━━━━━━━━
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容