static--Android靜態變量使用陷阱


   

 相關資料:http://blog.csdn.net/ctcwri/article/details/8858414

                    http://blog.csdn.net/weihan1314/article/details/8033052

                    http://www.2cto.com/kf/201205/133951.html

靜態變量大家再熟悉不過了,本來沒什么好重復的。事情起因是這樣的,最近測試那邊反應正在做的一個產品總是莫名其妙的顯示不出某些數據,甚至閃退崩潰,仔細查了幾遍發現沒什么問題,最后百般周折發現在那部測試機上運行的時候才會出現這中問題。於是各種log,各種斷點調試,最后發現都是報的java.lang.NullPointerException,發現是靜態變量的問題,想想不至於啊...

      bug原因,測試妹紙用的那部測試機常年用於測試,副職公用手機,里面大家裝了各種應用,大概不下50多個應用,雖然手機是1G RAM,但是也經不起這么造,可用內存極小。調試的時候發現誇張的時候,返回到前一個Activity,后面的馬上就被回收了。雖然看起來是外因,但還是得改啊。總結:Android手機在可用內存及其小的時候,會回收everything,是everything當然包括static。

      怎么解決呢,各種求解。Android是用Java開發,其靜態變量的生命周期遵守Java的設計。static 修飾的靜態變量,使用很方便,在不同的類和包中都可以使用,在虛擬機中單獨占用內存,沒錯,這些都是它們的優點,我們知道靜態變量是在類被load的時候分配內存的,並且存在於方法區。當類被卸載的時候,靜態變量被銷毀。在PC機的客戶端程序中,一個類被加載和卸載,可簡單的等同於jvm進程的啟動和結束。那么在Android中呢?用的Dalvik vm也是一樣的。不過Android不太突出的進程概念,所以對靜態變量的生命周期就會感覺模糊,這種模糊對於值類型是無所謂的,如果是靜態的對象引用,則與內存回收、內存泄漏這些問題有關,有必要加深研究和理解。靜態變量在類被加載的時候分配內存。類在什么時候被加載?當我們啟動一個app的時候,系統會創建一個進程,此進程會加載一個Dalvik VM的實例,然后代碼就運行在DVM之上,類的加載和卸載,垃圾回收等事情都由DVM負責。也就是說在進程啟動的時候,類被加載,靜態變量被分配內存。靜態變量在類被卸載的時候銷毀,類在什么時候被卸載?在進程結束的時候,一般情況下,所有的類都是默認的ClassLoader加載的,只要ClassLoader存在,類就不會被卸載,而默認的ClassLoader生命周期是與進程一致的。Android中的進程什么時候結束,這個是Android對進程和內存管理不同於PC的核心——如果資源足夠,Android不會殺掉任何進程,另一個意思就是進程隨時可能會被殺掉。而Android會在資源夠的時候,重啟被殺掉的進程。也就是說靜態變量的值,如果不做處理,是不可靠的,可以說內存中的一切都不可靠。如果要可靠,還是得保存到Nand或SD卡中去,在重啟的時候恢復回來。另一種情況就是不能把退出所有Activity等同於進程的退出,所以在用戶點擊圖標啟動應用的時候以前存放於靜態變量中的值,有可能還存在,因此要視具體情況給予清空操作。

      解決方案,兩種思路:

      一、根據Google官方的推薦以及百度到的各位大神的推薦,我們應該盡量使用繼承自Application的自定義類,在我們繼承的類中定義需要全局使用的變量,並通過getApplicationContext()來獲取和保存相關的變量即可。

比如:

public class TestApplication extends Application { 
  private int curIndex; 
  public int getCurIndex() { 
  return curIndex; 
  } 
  public void setCurIndex(int curIndex) { 
  this.curIndex = curIndex; 
  } 
  @Override 
  public void onCreate() { 
  super.onCreate(); 
  } 
  @Override 
  public void onTerminate() { 
  super.onTerminate(); 
  } 
  } 


使用方法:

       //保存變量 
      application.setCurIndex(5); 
      //獲取變量 
      application.getCurIndex(); 

      TestApplication application = (TestApplication) this.getApplicationContext(); 
      Application是與應用同時存在的,也就是應用在它就在,並不會被GC給莫名其妙的回收掉,因此,使用此方法更加安全的穩妥。本人最后采用的是這種方法,未發現問題。

      二、觀點不太一樣,甚至和第一種有點小沖突

      Application也是一樣不可靠,Application其實是一個單例對象,也是放在內存中的,當進程被殺掉,就全清空了,只不過Android系統會幫重建Application,而我們存放在Application的數據自然就沒有了,還是得自己處理。靜態引用的對象不會被垃圾回收,只要靜態變量沒有被銷毀也沒有置null,其對象一直被保持引用,也即引用計數不可能是0,因此不會被垃圾回收。因此,單例對象在運行時不會被回收。

     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM