內(nèi)存泄漏和內(nèi)存溢出是兩個概念格侯。
內(nèi)存泄漏鼻听,指的是程序使用過的內(nèi)存“忘記”歸還給系統(tǒng)财著,造成長時間無謂地占用。
內(nèi)存溢出撑碴,指的是內(nèi)存被大量的使用后撑教,程序再次去申請內(nèi)存時,系統(tǒng)已經(jīng)不能滿足其要求的情況醉拓。
所以伟姐,內(nèi)存泄露到一定程度就會導(dǎo)致內(nèi)存溢出。
Java中亿卤,內(nèi)存的回收工作是GC來做的愤兵。GC也有軟肋:如果持有對象的強(qiáng)引用,GC是無法在內(nèi)存中回收這個對象的排吴。
繞個遠(yuǎn)說說幾種引用:
- 強(qiáng)引用(StrongReference)
強(qiáng)引用是使用最普遍的引用秆乳。如果一個對象具有強(qiáng)引用,那垃圾回收器絕不會回收它钻哩。當(dāng)內(nèi)存空間不足矫夷,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯誤,使程序異常終止憋槐,也不會靠隨意回收具有強(qiáng)引用的對象來解決內(nèi)存不足的問題双藕。 - 軟引用(SoftReference)
如果一個對象只具有軟引用,則內(nèi)存空間足夠阳仔,垃圾回收器就不會回收它忧陪;如果內(nèi)存空間不足了,就會回收這些對象的內(nèi)存近范。 - 弱引用(WeakReference)
GC掃描過程中嘶摊,一旦發(fā)現(xiàn)了只具有弱引用的對象,不管當(dāng)前內(nèi)存空間足夠與否评矩,都會回收它的內(nèi)存叶堆。 - 虛引用(PhantomReference)
如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣斥杜,在任何時候都可能被垃圾回收器回收虱颗。
列舉經(jīng)常造成內(nèi)存泄漏的幾種情況:
- static變量
- static activity
public class MyActivity extends BaseActivity {
static Activity mActivity = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivity = this;
}
}
通常,一個activity對象包含了大量的引用蔗喂,如果賦值給一個靜態(tài)變量會使activity脫離系統(tǒng)的管理忘渔。被泄漏的activity對象會一直存活在內(nèi)存中,造成內(nèi)存泄漏缰儿。
- static view
public class MyActivity extends BaseActivity {
static TextView textView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView = new TextView(this);
}
}
- 內(nèi)部類
內(nèi)部類使用起來是比較便捷的畦粮,但就是這么一點福利也要冒著內(nèi)存泄漏的風(fēng)險,因為非靜態(tài)的內(nèi)部類會持有外部類的一個隱式引用。
- Thread
public class MyActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
doSth();
}
private void doSth() {
new Thread() {
@Override
public void run() {
while (true) {
SystemClock.sleep(1000);
}
}
}.start();
}
}
假如新線程執(zhí)行的任務(wù)非常耗時宣赔,十天半個月都做不完预麸。在此期間,外部類對象也不能被回收儒将。TimerTask和AsyncTask也會有同樣的問題师崎。
- Handler
public class MyActivity extends BaseActivity {
Handler mHanlder = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
doSth();
}
private void doSth() {
mHanlder.postDelayed(new Runnable() {
@Override
public void run() {
}
}, Long.MAX_VALUE >> 1);
}
}
Runnable會持有外部類引用,造成內(nèi)存泄漏椅棺。
- Sensor Manager
通過Context.getSystemService(int name)可以獲取系統(tǒng)服務(wù)。這些服務(wù)工作在各自的進(jìn)程中齐蔽,幫助應(yīng)用處理后臺任務(wù)两疚,處理硬件交互。如果需要使用這些服務(wù)含滴,可以注冊監(jiān)聽器诱渤,這會導(dǎo)致服務(wù)持有了Context的引用,如果在Activity銷毀的時候沒有注銷這些監(jiān)聽器谈况,會導(dǎo)致內(nèi)存泄漏勺美。
public class MyActivity extends BaseActivity implements SensorEventListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
registerListener();
}
void registerListener() {
SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);
}
@Override
public void onSensorChanged(SensorEvent event) {
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
恩,就醬碑韵。