2011年11月19日 星期六

千萬別相信 Android 上的應用程式

Standard
或許有些過於危言聳聽,但我們確實得正視這樣的議題:『資料無故從手機中消失』。這是可能發生的問題,原因在於 Android Dalvik VM 的 Garbage Collection 機制太過強大,如果程式開發者在寫程式的過程中都沒注意到這問題,那這肯定是個不定時炸彈。

話說,寫過 Android Application 的人應該都很習慣了變數宣告後,用完了就不管他,彷彿系統會有無限量供應的記憶體一般。不過,這對『慣C』一族來說,永遠是種荒繆的事,實在無法想像『憑什麼』不用釋放記憶體。其實說穿了,這一切是 VM 裡面的 Garbage Collection 在『Hold 住』場面,他會自動將目前 Reference 數量稀少的記憶體回收,以避免系統記憶體被用光後又不釋放。而所有回收的動作,有一系列『聰明』的演算法,有興趣的人可以自己去找相關資訊閱讀。

但是別以為 Garbage Collection 可以聰明到百分之百準確知道,什麼東西回收後是對系統或是應用程式無傷的,因為這就算要人腦來判斷,也一定會犯錯。更者,也別以為 Garbage Collection 不太會動當前正在跑的程式,因為只要符合條件,就算是你程式當前不斷在用的變數,也可能消失被回收,導致程式錯亂,就像被鬼憑空抓走一般。

如果你認為這只是理論,那你就錯了,這問題實際發生在最近筆者幫忙救火的案子裡。詳細情況是,這是瀏覽器相關的案子,當時我們宣告了幾個 Private 變數,然後使該變數在使用者操作觸發後,會被設定了一些數值供接下來的許多運算使用。一般情況下,我們實作的程式都很正常,不過,一旦開到比較複雜或充滿 JavaScript 的網站後,我們的程式彷彿就開始像中邪,完全不照我們的想像去執行,無論怎麼找問題,也找不出個所以然。

由於問題的發生是過程中變數無故被歸零,而我們又確定沒有任何一段自己的程式會讓他歸零,所以只剩下一種可能:『Garbage Collection 為了因應 WebView 過多的需求,而把變數給回收了。』

最後,我們將這變數設為 static 以解決這問題。不過,雖然用 static 暫時解決了問題,那也只是減少變數不被回收的機會,並不是最妥當的做法。

後記

別小看這問題,其實在 Android Framework 中也處處藏滿類似的問題,只是不知道什麼時候會爆出來而已。而這次救火的案子,就倒霉碰到鬼。

或許多半處於最上層的應用程式開發者,都覺得這些底下的事情,應該極穩定又可信賴,從來就不會在意這些東西,但是這可能會造成重大問題,相關知識還是要多充實。