泄露對象是什么
三種內(nèi)存分配
- 靜態(tài)存儲區(qū) : 靜態(tài)數(shù)據(jù)、全局static數(shù)據(jù)和常量
- 棧區(qū) : 在執(zhí)行函數(shù)時,函數(shù)內(nèi)局部變量的存儲單元
- 堆區(qū) : 程序運行 new 的內(nèi)存
public class A{
//成員變量全部存儲在堆中(包括基本數(shù)據(jù)類型,引用和引用的對象實體)
//因為它們屬于類,類對象終究是要被new出來使用的。
int a = 1;
Obj f = new Obj();
public void foo(){
//局部變量的基本數(shù)據(jù)類型和引用存儲于棧中
int b = 2;
//new 出的對象實體存儲于堆中
Obj o = new Obj();
}
}
// aObj 這個引用存在棧中
// aObj new 出的對象存在堆中
A aObj = new A();
內(nèi)存泄露只針對堆內(nèi)存
內(nèi)存為什么會泄露
對象可達性判斷
如果一個對象具有一個或多個引用,稱這個對象是可達的。
如上面的例子 A aObj = new A(); JVM堆區(qū) 存儲新創(chuàng)建的 A 的實例, 棧區(qū)存放 aObj(引用),存放的是 A 實例的地址。
此時,A 的實例是可達的,因為有 aObj 這個引用指向它。
內(nèi)存回收機制
Java的內(nèi)存垃圾回收機制是從程序的主要運行對象(如靜態(tài)對象/寄存器/棧上指向的堆內(nèi)存對象等)開始檢查引用鏈,當遍歷一遍后得到上述這些可達對象組成無法回收的對象集合,而其他孤立的不可達對象就作為垃圾回收。
實例
private static PopSharedPreferences instance = null;
private static Context mContext = null;
public static PopSharedPreferences getInstance(Context context) {
if (instance == null) {
instance = new PopSharedPreferences(context);
}
return instance;
}
private PopSharedPreferences(Context context) {
this.mContext = context;
....
}
public class PopAudioPlayer extends HomeAsBackActivity implements PopWindowParent {
@Override
protected void onCreate(Bundle icicle) {
mPreferences = PopSharedPreferences.getInstance(this);
}
}
GC ROOTS --> .... --> PopSharedPreferences --> mContext --> PopAudioPlayer
PopAudioPlayer 銷毀 ,但是 mContext 被 PopSharedPreferences 靜態(tài)實例持有。 GC 無法回收 PopAudioPlayer 對象占用的堆內(nèi)存。
mContext 改成 ApplicationContext 打斷了 PopSharedPreferences 對象和 PopAudioPlayer 對象的引用關系。
強引用、軟引用、弱引用和虛引用
- 強引用 用的大部分都是強引用,new 一個對象等。 GC 不會回收。
- 軟引用
SoftReference如果內(nèi)存空間足夠,垃圾回收器就不會回收它,如果內(nèi)存空間不足了,就會回收這些對象的內(nèi)存。 - 弱引用
WeakReference在垃圾回收器掃描過程中,一旦發(fā)現(xiàn)了只具有(僅有)弱引用的對象,不管當前內(nèi)存空間是否足夠都會被回收。 - 虛引用
PhantomReference如果一個對象僅持有虛引用,那么這個對象就如同沒有任何引用一樣,隨時可能被GC回收。主要用來跟蹤對象被GC回收的過程。