站內搜尋

2015/4/2

[Java] Android Tip - 有關 Singletons pattern 的小研究

在 Android 上寫 Singletons Class 的時候,總會有些小問題困擾我。
到底 Static final Object 什麼時候會被載入?又會不會被系統給 GC 掉呢?

底下是一個常見的 Singletons pattern 寫法
public class SingletonClass
{
    private static final SingletonClass mInstance = new SingletonClass();
    public static SingletonClass getInstance()
    {
        return mInstance;
    }
}
這幾乎已經是從小寫到大的標準寫法(從不知道這叫 Singleton pattern 寫到知道這叫 Singleton pattern ...),但有時還是會不自覺的好奇了一下。

到底 SingletonClass 會不會被釋放掉呢?假設目前都沒有任何的 Object reference 到 SingetonClass,為什麼它不會被釋放掉?

在 Android 這個平台上,其實很容易一個不小心就被一些奇奇怪怪的記憶體問題給玩死,因些在這時間點上,又更容易產生這個好奇。

因些,就上了 Google 大神的神壇,好好的問了一卦,最後讓我找到一個相當不錯的教學文。
Java Tip 52: Singletons vs. class (un)loading
裡面對 class loader 載入 class 及釋放的時間有了一些簡單的論述,相當的有用,其中有幾個有趣的重點:
  1. 在 Java 1.0 之前,這個 SingletonClass 的寫法完全可以動,因為.. class unloading 根本沒實做..哈哈哈,太酷
  2. 但很機巴的在 Java 1.1.x 的時候,System class loader 裡面的 unloading 被弄出來了,而且,完全照著規距來。
    也就是說,假設沒有任何的 GC root reference 到 SingletonClass 的 instance 了話,SingletonClass 有機會被系統給幹掉。
  3. 上頭說的 Java 1.1.x 很明顯的是被公幹了,因此,在 Java 1.2 的時候,規則又改啦~~而且這次的改法友善許多。
    1. 只要是被 system class loader 給 load 上來的 classes,class loader 就不會沒事跑去把你 unload 掉,所以你的 SingletonClass 不會沒事就被系統拿去種。
    2. 被其它 class loader load 上來的 classes,只有在該 class loader 被 unloaded 掉時,才會被 unload。這也某種程度上的保護了 Java 設計師不用擔心太多記憶體問題
事已至此,相信各位 Android 工程師們,大概心底也有個底了,SingletonClass 的這個寫法,應該是沒有什麼大問題。

但好玩的事情就是常常發生在這個時候....
啊我常用的 Singleton class,都需要我帶入 Context 呀!!!!
怎麼辨???
一般 Android App 在沒有任何 Component 被系統給叫醒時,是沒有 Context 可用的,那我該怎麼生成我那該死的 Singleton class??

我相信解決的方式是很多,以下是我個人最近在用的寫法,就也提供給大家參考吧。
public class SingletonClass
{
    private static final SingletonClass mInstance = new SingletonClass();
    private Context mContext;
    public static SingletonClass getInstance()
    {
        // if (mInstance == null) throw new RuntimeException("Are you kidding me??");  
        return mInstance;
    }
    /* Package Private */ static void setup(Context c)
    {
        mInstance = new SingletonClass(c)
    }
    private static SingletonClass(Context c)
    {
        mContext = c;
    }
}
// 然後在 Application 物件中做 initialize
public class SingletonDemoApp extends Application
{
    @Override
    public void onCreate()
    {
        super.onCreate();
        SingletonClass.setup(this);
    }
}

End.

Reference:
Java Tip 52: Singletons vs. class (un)loading

熱門文章