內(nèi)存泄漏和內(nèi)存溢出的關(guān)系
- 內(nèi)存泄漏: 是指申請(qǐng)空間后,在使用完后沒有釋放。
- 內(nèi)存溢出: 程序向系統(tǒng)申請(qǐng)的內(nèi)存超過(guò)了內(nèi)存所能分配的大小(OOM)。
- 內(nèi)存泄漏會(huì)導(dǎo)致程序運(yùn)行變慢,影響體驗(yàn)程度。大量的內(nèi)存泄露會(huì)導(dǎo)致內(nèi)存溢出(oom)。
內(nèi)存泄漏的主要原因
- 持有對(duì)象的強(qiáng)引用,沒有及時(shí)釋放
導(dǎo)致內(nèi)存泄漏的案例分析
- 寫單列工具類,如:
private static WifiUtils mInstant = null; //全局靜態(tài)變量
public static WifiUtils getInstant(Context context) {
if (mInstant == null) {
synchronized (WifiUtils.class) {
if (mInstant == null) {
mInstant = new WifiUtils(context);
}
}
}
return mInstant;
}
上面可能是我們寫的一個(gè)獲取單列引用的方法,單獨(dú)這樣看應(yīng)該沒有任何問(wèn)題。但是當(dāng)我們?cè)赼ctivity中去調(diào)用
WifiUtils.getInstant(this)
這樣就會(huì)造成內(nèi)存泄漏了。
1. 原因:
WifiUtils的對(duì)象是全局static的,創(chuàng)建后其生命周期是伴隨程序一直存在的。但他保留了activity的一個(gè)強(qiáng)引用,所以當(dāng)activity需退出時(shí),導(dǎo)致無(wú)法銷毀或被回收。
2.解決方案
解決的方案很多,這里舉兩種常用的:
( 1 )、把context 改成 context.getApplicationContext()。這樣并不是所以的地方度可以這樣做,但是一般的工具類可以這樣。
(2)、在activity的時(shí)候退出,銷毀mInstant對(duì)象。android中registerListener和unregisterListener 的做法就和這個(gè)一樣。
編碼的時(shí)候時(shí)刻注意以下容易出現(xiàn)內(nèi)存溢出的情況
1、帶有全局static變量
2、Inner Classes
private static Object inner;
void createInnerClass() {
class InnerClass {
}
inner = new InnerClass();
}
void paly(){
createInnerClass();//創(chuàng)建內(nèi)部類對(duì)象
}
3、Anonymous Classes
void startAsyncTask() {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
while(true);
}
}.execute();
}
void paly(){
startAsyncTask();//task執(zhí)行任務(wù)的時(shí)候,activity無(wú)法退出,直到任務(wù)執(zhí)行結(jié)束
}
4、Threads、TimerTask、Handler 這幾個(gè)有點(diǎn)類試,都是在執(zhí)行任務(wù)的時(shí)候,對(duì)activity保持著強(qiáng)引用,所以在退出的時(shí)候,要注意銷毀,防止內(nèi)存泄漏。
內(nèi)存泄漏的規(guī)避
內(nèi)存泄漏無(wú)疑會(huì)給我們的程序帶來(lái)諸多的問(wèn)題。但是,只要我們記住 "當(dāng)當(dāng)前的對(duì)象要銷毀時(shí),沒有其他地方對(duì)其有強(qiáng)引用,如果有需要先把引用的地方釋放或者銷毀 ” 這樣就會(huì)大大減少內(nèi)存泄漏的幾率。