1. 程式人生 > >Android中靜態變數的生命週期

Android中靜態變數的生命週期

靜態變數的生命週期,起始於類的載入,終止於類的釋放。
什麼時候類會載入呢?
我們知道,在app開啟時,會建立一個程序,然後初始化一個dvm的例項,負責類的載入釋放 和 垃圾回收等。
換句話說,在程序建立之後,就會載入類,靜態變數誕生了。
那何時釋放?
當然是在類解除安裝的時候。同上面。在程序結束之前,靜態變數就壽終正寢。
我們知道,Android中,你是不知道何時程序會被Kill。所以
1.不能保證靜態變數會一直存在.(程序可能被Kill掉)
2.每次開啟app時靜態變數的值都是初始值(程序沒有被kill掉所以靜態變數儲存的還是上次的值)。
而且,靜態變數是不會被垃圾回收的,其物件一直保持引用,及ARC不可能是0。
所以要自己釋放靜態變數。

網上查到的相關連結

1
單例模式討論篇:單例模式與垃圾回收

Jvm的垃圾回收機制到底會不會回收掉長時間不用的單例模式物件,這的確是一個比較有爭議性的問題。將這一部分內容單獨成篇的目的也是為了與廣大博友廣泛的討論一下這個問題。為了能讓更多的人看到這篇文章,請各位博友看完文章之後,點一下“頂”,讓本篇文章排名儘量的靠前。筆者在此謝過。
討論命題:當一個單例的物件長久不用時,會不會被jvm的垃圾收集機制回收。
首先說一下為什麼會產生這一疑問,筆者本人再此之前從來沒有考慮過垃圾回收對單例模式的影響,直到去年讀了一本書,《設計模式之禪》秦小波著。在書中提到在j2ee應用中,jvm垃圾回收機制會把長久不用的單例類物件當作垃圾,並在cpu空閒的時候對其進行回收。之前讀過的幾本設計模式的書,包括《java與模式》,書中都沒有提到jvm垃圾回收機制對單例的影響。並且在工作過程中,也沒有過單例物件被回收的經歷,加上工作中很多前輩曾經告誡過筆者:儘量不要宣告太多的靜態屬性,因為這些靜態屬性被載入後不會被釋放。因此對jvm垃圾收集會回收單例物件這一說法持懷疑態度。漸漸地,發現在同事中和網上的技術人員中,對這一問題也基本上是鮮明的對立兩派。那麼到底jvm會不會回收長久不用的單例物件呢。
對這一問題,**筆者本人的觀點是:不會回收**。
下面給出本人的測試程式碼
[java] view plaincopy
class Singleton {

private byte[] a = new byte[6*1024*1024];

private static Singleton singleton = new Singleton();

private Singleton(){}

1
2
3
public static Singleton getInstance(){  
    return singleton;  
}  

}

class Obj {

private byte[] a = new byte[3*1024*1024];

}

public class Client{

public static void main(String[] args) throws Exception{

Singleton.getInstance();

while(true){

new Obj();

}

}

}

本段程式的目的是模擬j2ee容器,首先例項化單例類,這個單例類佔6M記憶體,然後程式進入死迴圈,不斷的建立物件,逼迫jvm進行垃圾回收,然後觀察垃圾收集資訊,如果進行垃圾收集後,記憶體仍然大於6M,則說明垃圾回收不會回收單例物件。
執行本程式使用的虛擬機器是hotspot虛擬機器,也就是我們使用的最多的java官方提供的虛擬機器,俗稱jdk,版本是jdk1.6.0_12
執行時vm arguments引數為:-verbose:gc -Xms20M -Xmx20M,意思是每次jvm進行垃圾回收時顯示記憶體資訊,jvm的記憶體設為固定20M。
執行結果:
……
[Full GC 18566K->6278K(20352K), 0.0101066 secs]
[GC 18567K->18566K(20352K), 0.0001978 secs]
[Full GC 18566K->6278K(20352K), 0.0088229 secs]
……
從執行結果中可以看到總有6M空間沒有被收集。因此,筆者認為,至少在hotspot虛擬機器中,垃圾回收是不會回收單例物件的。
後來查閱了一些相關的資料,hotspot虛擬機器的垃圾收集演算法使用根搜尋演算法。這個演算法的基本思路是:對任何“活”的物件,一定能最終追溯到其存活在堆疊或靜態儲存區之中的引用。通過一系列名為根(GC Roots)的引用作為起點,從這些根開始搜尋,經過一系列的路徑,如果可以到達java堆中的物件,那麼這個物件就是“活”的,是不可回收的。可以作為根的物件有:
虛擬機器棧(棧楨中的本地變量表)中的引用的物件。
方法區中的類靜態屬性引用的物件。
方法區中的常量引用的物件。
本地方法棧中JNI的引用的物件。
方法區是jvm的一塊記憶體區域,用來存放類相關的資訊。很明顯,java中單例模式建立的物件被自己類中的靜態屬性所引用,符合第二條,因此,單例物件不會被jvm垃圾收集。
雖然jvm堆中的單例物件不會被垃圾收集,但是單例類本身如果長時間不用會不會被收集呢?因為jvm對方法區也是有垃圾收集機制的。如果單例類被收集,那麼堆中的物件就會失去到根的路徑,必然會被垃圾收集掉。對此,筆者查閱了hotspot虛擬機器對方法區的垃圾收集方法,jvm解除安裝類的判定條件如下:
該類所有的例項都已經被回收,也就是java堆中不存在該類的任何例項。
載入該類的ClassLoader已經被回收。
該類對應的java.lang.Class物件沒有任何地方被引用,無法在任何地方通過反射訪問該類的方法。
只有三個條件都滿足,jvm才會在垃圾收集的時候解除安裝類。顯然,單例的類不滿足條件一,因此單例類也不會被解除安裝。也就是說,只要單例類中的靜態引用指向jvm堆中的單例物件,那麼單例類和單例物件都不會被垃圾收集,依據根搜尋演算法,物件是否會被垃圾收集與未被使用時間長短無關,僅僅在於這個物件是不是“活”的。假如一個物件長久未使用而被回收,那麼收集演算法應該是最近最長未使用演算法,最近最長未使用演算法一般用在作業系統的內外存交換中,如果用在虛擬機器垃圾回收中,豈不是太不安全了?以上是筆者的觀點。

二(轉載)Android靜態變數的生命週期

Android是用Java開發,其靜態變數的生命週期遵守Java的設計。我們知道靜態變數是在類被load的時候分配記憶體的,並且存在於方法區。當類被解除安裝的時候,靜態變數被銷燬。在PC機的客戶端程式中,一個類被載入和解除安裝,可簡單的等同於jvm程序的啟動和結束。那麼在Android中呢?用的Dalvik vm也是一樣的。不過Android不太突出的程序概念,所以對靜態變數的生命週期就會感覺模糊,這種模糊對於值型別是無所謂的,如果是靜態的物件引用,則與記憶體回收、記憶體洩漏這些問題有關,有必要加深研究和理解。

一、靜態變數在類被載入的時候分配記憶體。

類在什麼時候被載入?

當我們啟動一個app的時候,系統會建立一個程序,此程序會載入一個Dalvik VM的例項,然後程式碼就執行在DVM之上,類的載入和解除安裝,垃圾回收等事情都由DVM負責。也就是說在程序啟動的時候,類被載入,靜態變數被分配記憶體。

二、靜態變數在類被解除安裝的時候銷燬。

類在什麼時候被解除安裝?

在程序結束的時候。

說明:一般情況下,所有的類都是預設的ClassLoader載入的,只要ClassLoader存在,類就不會被解除安裝,而預設的ClassLoader生命週期是與程序一致的,本文討論一般情況。

三、Android中的程序什麼時候結束

這個是Android對程序和記憶體管理不同於PC的核心——如果資源足夠,Android不會殺掉任何程序,另一個意思就是程序隨時可能會被殺掉。而Android會在資源夠的時候,重啟被殺掉的程序。也就是說靜態變數的值,如果不做處理,是不可靠的,可以說記憶體中的一切都不可靠。如果要可靠,還是得儲存到Nand或SD卡中去,在重啟的時候恢復回來。

另一種情況就是不能把退出所有Activity等同於程序的退出,所以在使用者點選圖示啟動應用的時候,以前存放於靜態變數中的值,有可能還存在,因此要視具體情況給予清空操作。

四、Application也是一樣不可靠

Application其實是一個單例物件,也是放在記憶體中的,當程序被殺掉,就全清空了,只不過Android系統會幫重建Application,而我們存放在Application的資料自然就沒有了,還是得自己處理。

五、靜態引用的物件不會被垃圾回收

只要靜態變數沒有被銷燬也沒有置null,其物件一直被保持引用,也即引用計數不可能是0,因此不會被垃圾回收。因此,單例物件在執行時不會被回收。

相關推薦

Android靜態變數生命週期

靜態變數的生命週期,起始於類的載入,終止於類的釋放。 什麼時候類會載入呢? 我們知道,在app開啟時,會建立一個程序,然後初始化一個dvm的例項,負責類的載入釋放 和 垃圾回收等。 換句話說,在程序建立之後,就會載入類,靜態變數誕生了。 那何時釋放? 當然是在類解除安裝的

當一個類被載入後,它的靜態變數生命週期是什麼,是整個應用程式執行結束(比如java web程式,從類載入到伺服器關閉還是該執行緒執行完畢)還是別的什麼?

靜態變數在記憶體中只有一個,JAVA虛擬機器載入類的時候為其分配記憶體,位於方法區,被類的所有例項共享,其生命週期取決於類的生命週期。。。當類被解除安裝。。。靜態變數也被銷燬 取決於類載入器。如果換了一個類載入器,這個

Android的Activity生命週期

       說到生命週期,對於程式設計師來說並不陌生。如果學過Servlet的朋友,就更不會陌生了餓,其實差不多,android的生命週期與Servlet的生命週期有相似之處 。             Android的生命週期通常是有這樣幾個方法構成:onCreate()、onStart()、onPau

java 靜態變數生命週期(類生命週期

引言         最近有位細心的朋友在閱讀筆者的文章時,對java類的生命週期問題有一些疑惑,筆者開啟百度搜了一下相關的問題,看到網上的資料很少有把這個問題講明白的,主要是因為目前國內java方面的教材大多隻是告訴你“怎樣做”,但至於“為什麼這樣做”卻不多說,所以造成大家在基礎和原理方面的知識比較匱乏,

static 靜態變數生命週期。-=---

靜態變數的型別說明符是static。靜態變數當然是屬於靜態儲存方式,但是屬於靜態儲存方式的量不一定就是靜態變數,例如外部變數雖屬於靜態儲存方式,但不一定是靜態變數,必須由 static加以定義後才能成為靜態外部變數,或稱靜態全域性變數。對於自動變數,它屬於動態儲存方式。但是也可以用static定義它為靜態自

Java 靜態變數生命週期

Static: 載入:java虛擬機器在載入類的過程中為靜態變數分配記憶體。類變數:static變數在記憶體中只有一個,存放在方法區,屬於類變數,被所有例項所共享銷燬:類被解除安裝時,靜態變數被銷燬,並釋放記憶體空間。static變數的生命週期取決於類的生命週期類初始化順序: 靜態變數、靜態程式碼塊初始化

Android服務的生命週期與兩種方式的區別

服務的生命週期跟Activity的生命週期類似。但是生命週期甚至比你關注服務如何建立和銷燬更重要,因為服務能夠在使用者不知情的情況下在後臺執行。 服務的生命週期---從建立到銷燬---可以被分為以下兩個路徑: 1.  啟動型別的服務: onCreate()- >onSt

Android的activity的生命週期解析

Android官方文件和其他不少資料都對Activity生命週期進行了詳細介紹,在結合資料和專案開發過程中遇到的問題,本文將對Activity生命週期進行一次總結。 Activity是由Activity棧進管理,當來到一個新的Activity後,此Activity將被加入到Activit

知識儲備:SpringBean的生命週期(基於註解版)

一:前言 在Spring專案中,通常配置Spring都是使用XML的形式進行配置,配置bean是通過<bean></bean>標籤將bean加入IOC容器中,但在Spring註解版中,可以通過Java程式碼進行配置,即建立一個java類在其類頭上標註@Configurat

java靜態變數靜態程式碼塊,靜態方法,例項變數,匿名程式碼塊的載入順序

1. java中靜態變數,靜態程式碼塊,靜態方法,例項變數,匿名程式碼塊 在Java中,使用{}括起來的程式碼稱為程式碼塊,程式碼塊可以分為以下四種: (1)普通程式碼塊:就是類中方法的方法體 public void xxx(){ //code }

Android viewPager Fragment 切換生命週期

記錄一下: 場景: 上面是一個很常見的一個切換效果:結果一般都是一個主Activity,裡面佈局了一個TabLayout+ViewPager,ViewPager裡面添加了4個Fragment,假如日期時間為A,聲音設定為B 開關機設定為C,認證模式 為D 第一步:列印一下主要的Log

C#靜態變數靜態方法的說明

1.靜態變數在C#程式中,沒有全域性變數的概念,這意味著所有的成員變數只有該類的例項才能操作這些資料,這起到了“資訊隱藏”的作用。但有些時候,這樣做卻不是個明智的選擇。假設我們要定義一個圖書類,要求該類能儲存圖書的數量,即每增加一本圖書(定義一個例項),圖書的數量應該加1。如果沒有靜態變數,我們需要將圖書的數

C#靜態變數靜態方法

C#中靜態變數和 靜態方法 static節省了構造物件時造成的效能損耗,其次還能用於一些特殊環境(如惡漢式單例) 但是由於靜態成員在程式載入之前就進入記憶體,直到程式結束才會銷燬,所以 在程式中如果大量使用static來宣告型別或成員,也會造成系統資源的浪費。 一般靜態的就代表全域性。表示任何類

spring_(10)IOC容器Bean的生命週期

SpringIOC容器可以管理Bean的生命週期,Spring允許在Bean生命週期的特定點執行定製的任務 SpringIOC容器對Bean的生命週期進行管理的過程: 通過構造器或工廠方法建立Bean例項 為Bean的屬性設定值和對其他Bean的引

Java靜態變數的宣告位置

Java中靜態變數只能是成員變數,區域性方法中的區域性變數除final外不能有任何其他修飾符,例如: 1 public class Test { 2 static String x = "1"; 3 static int y = 1; 4 5 public

【Django】Django請求的生命週期

Django的請求生命週期是指當用戶在瀏覽器上輸入url到使用者看到網頁的這個時間段內,Django後臺所發生的事情 1. 當用戶在瀏覽器中輸入url時,瀏覽器會生成請求頭和請求體發給服務端 請求頭和請求體中會包含瀏覽器的動作(action),這個動作通常為get或者post,體現在url之中。 2. u

java靜態變數與非靜態變數的區別

靜態變數與非靜態變數的區別如下: 1.記憶體分配 靜態變數在應用程式初始化時,就存在於記憶體當中,直到它所在的類的程式執行結束時才消亡; 而非靜態變數需要被例項化後才會分配記憶體。 2.生存週期 靜態變數生存週期為應用程式的存在週期; 非靜態變數的存在週期取決於

springbaen的生命週期,及生命週期的作用

最近在看spring原始碼,所以總結下spring的生命週期和各個階段的作用。 spring的生命週期概括起來主要如下: 例項化 屬性注入 ioc注入 實現了BeanNameAware 則執行setBeanName方法  實現了BeanFactoryAw

springBean的生命週期,具體再具體

今天在面試的時候,面試官提問到spring中Bean的生命週期,我的回答是: 1.例項化(為bean物件開闢空間) 2.初始化(對物件的屬性進行依賴注入,使用setter方法) 3.銷燬 我以為週期這裡

Android學習筆記2-生命週期

元件的生命週期   應用程式元件都有一個生命週期,從響應Intent的Android例項開始到這個例項被銷燬。在這期間,他們或許有效或許無效,有效時或許對使用者可見或許不可見。下面我們就來討論四個基本元件的生命週期,包括在生命週期內的各種狀態,以及狀態之間的轉換。這幾種狀態可