討論篇:靜態變量生命週期到底何如?如何使用?

靜態變量的生命週期

​ 最近有個朋友問我個問題,爲何用靜態變量做爲一個標誌位存儲,可是時常數據丟失,有時候又是可行的,緣由究竟爲什麼。java

public static boolean flag = false
複製代碼

​ 熟悉Java內存模型的朋友都知道,靜態變量是存儲在方法區之中的,而靜態變量又屬於整個類的實例,那麼靜態變量整個的生命週期是什麼樣子,何時會被回收呢?在此以前其實沒有太多考慮這個問題,工做涉及到靜態變量的地方通常也就是單例模式,但也沒有出現過被回收的狀況,加上工做以來,不少前輩同事也教導過不要使用太多的靜態變量,因此,對這個問題本身也一直是隻知其一;不知其二,沒有認真思考這個問題,在此參考了一些資料,作一些記錄。算法

1.類的生命週期

上述也說道,靜態變量是屬於類的實例對象,因此靜態變量的生命週期實際也就是類的生命週期。bash

當咱們編寫一個Java的源文件後,通過編譯會生成一個後綴名爲class的文件,這種文件叫作字節碼文件,只有這種字節碼文件纔可以在Java虛擬機中運行,Java類的生命週期就是指一個class文件從加載到卸載的全過程。jvm

一個Java類的完整的生命週期會經歷加載、鏈接、初始化、使用、和卸載五個階段,這裏就不都進行討論了,咱們主要看加載和卸載兩個階段spa

1.1 加載

對於加載的時機,各個虛擬機的作法並不同,可是有一個原則,就是當jvm「預期」到一個類將要被使用時就會在使用它以前對這 個類進行加載。好比說,在一段代碼中出現了一個類的名字,jvm在執行這段代碼以前並不能肯定這個類是否會被使用到,因而,有些jvm會在執行前就加載這個類,而有些則在真正須要用的時候纔會去加載它,這取決於具體的jvm實現。咱們經常使用的hotspot虛擬機是採用的後者,就是說當真正用到一個類的時候纔對它進行加載。code

加載階段是類的生命週期中的第一個階段,加載階段以後,是鏈接階段。有一點須要注意,就是有時鏈接階段並不會等加載階段完 全完成以後纔開始,而是交叉進行,可能一個類只加載了一部分以後,鏈接階段就已經開始了。可是這兩個階段總的開始時間和完成時間老是固定的:加載階段老是在鏈接階段以前開始,鏈接階段老是在加載階段完成以後完成.對象

也就是相似懶加載的思想,在將要使用到的時候去加載這個類,這樣也能避免浪費內存資源,固然,具體的實現就取決於具體的Jvm了生命週期

1.2 卸載

jvm卸載類的斷定條件以下:參照hotspot虛擬機的一句話進程

1.該類全部的實例都已經被回收,也就是java堆中不存在該類的任何實例。
2.加載該類的ClassLoader已經被回收。
3.該類對應的java.lang.Class對象沒有任何地方被引用,沒法在任何地方經過反射訪問該類的方法。
複製代碼

從上面的條件能夠看到,一個類被卸載的條件仍是挺苛刻的,首先全部類的對象實例要被回收,兩者,加載該類的ClassLoader要被回收,這個條件就基本等同於進程掛掉,最後是Class對象無任何引用。內存

從上面結論基本能夠判斷,靜態變量的生命週期基本是從這個類加載,到整個進程死掉的過程,注意退出APK不表明殺死進程,這時候,靜態變量仍是有效的,進程重啓後靜態變量從新生成。依據根搜索算法,對象是否會被垃圾收集與未被使用時間長短無關,僅僅在於這個對象是否是「活」的。

同時咱們也應該注意到,靜態變量生命週期的如此之長,致使靜態變量基本很難被GC回收掉,是很是佔用內存的,因此在開發過程當中,儘可能少使用一些靜態屬性的變量,減小內存佔用。

以上也是僅表明我的意見,期待各位朋友的發言

相關文章
相關標籤/搜索