最近在研究內(nèi)存泄漏的過程中偶然發(fā)現(xiàn)一個問題:我們通過Builder這種構(gòu)建者的方式(這個Builder是個靜態(tài)內(nèi)部類)去構(gòu)建一個參數(shù)對象是否會引發(fā)內(nèi)存泄漏的風(fēng)險(即靜態(tài)內(nèi)部類的生命周期是怎樣的)?核心代碼如下:
public class ImageLoader {
private Context context;
public ImageLoader(Builder builder) {
this.context = builder.context;
}
public Context getContext() {
return context;
}
public static class Builder {
private Context context;
public Builder with(Context context) {
this.context = context;
return this;
}
public ImageLoader build() {
return new ImageLoader(this);
}
}
}
- 類似android中Dialog的創(chuàng)建,也是內(nèi)部維護了一個靜態(tài)內(nèi)部類Builder,通過實例化Buidler對象去設(shè)置各種參數(shù)俭识,最后通過build方法去實例化ImageLoader。不知道大家會不會跟我一樣霎终,會這么想:
1.靜態(tài)內(nèi)部類應(yīng)該是一開始就創(chuàng)建了并且會一直存在內(nèi)存中
2.所有的外部類實例共享這個靜態(tài)內(nèi)部類
3.靜態(tài)會不會造成我的上下文(假設(shè)傳遞過來的是activity對象)泄漏
帶著這些疑問喝滞,我做了如下的改動:
public class ImageLoader {
private Context context;
static {
Log.e("cyw", "ImageLoader靜態(tài)代碼塊");
}
public ImageLoader(){
Log.e("cyw", "ImageLoader構(gòu)造方法");
}
public ImageLoader(Builder builder) {
this.context = builder.context;
}
public Context getContext() {
return context;
}
public static class Builder {
private Context context;
static {
Log.e("cyw", "Builder靜態(tài)代碼塊");
}
public Builder(){
Log.e("cyw", "Builder構(gòu)造方法");
}
public Builder with(Context context) {
this.context = context;
return this;
}
public ImageLoader build() {
return new ImageLoader(this);
}
}
}
- 可以看到红竭,我在外部類和內(nèi)部類中分別加上了無參構(gòu)造方法和靜態(tài)代碼塊,并輸出相關(guān)日志变隔,最后规伐,我在主函數(shù)中實例化了外部類觀察日志輸出:
日志.png
- 通過日志,我們可以看到匣缘,靜態(tài)內(nèi)部類并沒有實例化也沒有執(zhí)行它的靜態(tài)代碼塊猖闪,至此我們可以得出第一個結(jié)論:靜態(tài)內(nèi)部類并不是一開始就創(chuàng)建的!它與靜態(tài)成員不一樣孵户,并不能直接通過外部類名.內(nèi)部類名的方式就可以直接訪問并得到它的對象萧朝,通俗一點來說就是:靜態(tài)內(nèi)部類跟正常的一個外部類一樣,它需要創(chuàng)建才能有夏哭!
- 既然得出了上面的結(jié)論,那么第二個問題也是一樣的道理献联,就是說:靜態(tài)內(nèi)部類并不會依賴于任何一個外部類實例竖配,它可以在適當?shù)臅r候被系統(tǒng)回收!所以這里自然也解答了第三個問題里逆,并不會造成內(nèi)存泄漏进胯!
- 所以,靜態(tài)內(nèi)部類對象的生命跟普通的對象一樣原押,生命開始于開發(fā)者創(chuàng)建它胁镐,結(jié)束于系統(tǒng)回收它!
-
最重要的一點:前面說不會造成內(nèi)存泄漏的前提是傳過來的對象(如context)沒有被靜態(tài)引用诸衔,也就是說Builder的context用靜態(tài)修飾而又處理不當可能會造成內(nèi)存泄漏盯漂!切記!