JVM調優精講-對象引用

1.Java對象的大小java

基本數據的類型的大小是固定的,這裏就很少說了。對於非基本類型的Java對象,其大小就值得商榷。在Java中,一個空Object對象的大小是8byte,這個大小隻是保存堆中一個沒有任何屬性的對象的大小。看
下面語句:
Object ob = new Object();
這樣在程序中完成了一個Java對象的生命,可是它所佔的空間爲:4byte+8byte。4byte是上面部分所說的Java棧中保存引用的所須要的空間。而那8byte則是Java堆中對象的信息。由於全部的Java非基本類型的對象都須要默認繼承Object對象,所以不論什麼樣的Java對象,其大小都必須是大於8byte。算法

有了Object對象的大小,咱們就能夠計算其餘對象的大小了。
Class NewObject {
int count;
boolean flag;
Object ob;
}
其大小爲:空對象大小(8byte)+int大小(4byte)+Boolean大小(1byte)+空Object引用的大小(4byte)=17byte。可是由於Java在對對象內存分配時都是以8的整數倍來分,所以大於17byte的最接近8的整數倍的是24,所以此對象的大小爲24byte。緩存


這裏須要注意一下基本類型的包裝類型的大小。由於這種包裝類型已經成爲對象了,所以須要把他們做爲對象來看待。包裝類型的大小至少是12byte(聲明一個空Object至少須要的空間),並且12byte沒有包含任何有效信息,同時,由於Java對象大小是8的整數倍,所以一個基本類型包裝類的大小至少是16byte。這個內存佔用是很恐怖的,它是使用基本類型的N倍(N>2),有些類型的內存佔用更是誇張(隨便想下就知道了)。所以,可能的話應儘可能少使用包裝類。在JDK5.0之後,由於加入了自動類型裝換,所以,Java虛擬機會在存儲方面進行相應的優化。jvm

2.引用類型優化

對象引用類型分爲:強引用、軟引用、弱引用、虛引用。線程

強引用:就是咱們通常聲明對象是時虛擬機生成的引用,強引用環境下,垃圾回收時須要嚴格判斷當前對象是否被強引用,若是被強引用,則不會被垃圾回收
軟引用:軟引用通常被作爲緩存來使用。與強引用的區別是,軟引用在垃圾回收時,虛擬機會根據當前系統的剩餘內存來決定是否對軟引用進行回收。若是剩餘內存比較緊張,則虛擬機會回收軟引用所引用的空間;若是剩餘內存相對富裕,則不會進行回收。換句話說,虛擬機在發生OutOfMemory時,確定是沒有軟引用存在的。
弱引用:弱引用與軟引用相似,都是做爲緩存來使用。但與軟引用不一樣,弱引用在進行垃圾回收時,是必定會被回收掉的,所以其生命週期只存在於一個垃圾回收週期內。code

虛引用: 與其餘幾種引用都不一樣,虛引用並不會決定對象的生命週期。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收器回收。對象

從上面的定義中能夠了解到,引用類型只和垃圾回收器回收規則,及jvm內存有關係。 當內存空間還足夠時,則能保留在內存之中;若是內存空間在進行垃圾收集後仍是很是緊張,則能夠拋棄這些對象 。在java虛擬機中如何判斷對象回收規則blog

3.引用計數法繼承

原理:給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任什麼時候刻計數器爲0的對象就是不可能再被使用的。

優勢:實現簡單,判斷效率高。

缺點:很難解決對象之間相互循環引用的問題。(主流Java虛擬機裏面沒有選用該種方法)。

4.可達性算法(根搜索算法)

原理:經過一系列的稱爲"GC Roots"的對象做爲起始點,從這些節點開始向下搜索,搜索所走過的路徑稱爲引用鏈,當一個對象到GC Roots沒有任何引用鏈相連(用圖論的話說,就是從GC Roots到這個對象不可達)時,則證實此對象是不可用的。

上圖中GC Root引用不可達,表示能夠回收的對象,若是GC Root引用可達,則對象還可存活。

可做爲GC Roots的對象包括下面幾種:

  • 虛擬機棧(棧幀中的本地變量表)中引用的對象。
  • 方法區中類靜態屬性引用的對象。
  • 方法區中常量引用的對象。
  • 本地方法棧中JNI(即通常說的Native方法)引用的對象

不管是經過引用計數算法判斷對象的引用數量,仍是經過根搜索算法判斷對象的引用鏈是否可達,斷定對象是否存活都與「引用」有關。

因此對象的引用可回收規則:強引用<軟引用<弱引用<虛引用

5.對象生命週期

咱們再從對象生命週期裏看對象回收的階段和對應的引用狀態

  1. 建立階段(Created):爲對象分配存儲空間,開始構造對象,從超類到子類對static成員進行初始化,超類成員變量按順序初始化,遞歸調用超類的構造方法,子類成員變量按順序初始化,子類構造方法調用,一旦對象被建立,並被分派給某些變量賦值,這個對象的狀態就切換到了應用階段
  2. 應用階段(In Use): 對象至少被一個強引用持有着。
  3. 不可見階段(Invisible): 當一個對象處於不可見階段時,說明程序自己再也不持有該對象的任何強引用,雖然該這些引用仍然是存在着的。
    簡單說就是程序的執行已經超出了該對象的做用域了。
  4. 不可達階段(Unreachable):
    對象處於不可達階段是指該對象再也不被任何強引用所持有。與「不可見階段」相比,「不可見階段」是指程序再也不持有該對象的任何強引用,這種狀況下,該對象仍可能被 JVM等系統下的某些已裝載的靜態變量或線程或 JNI等強引用持有着,這些特殊的強引用被稱爲」 GC root」。存在着這些 GC root會致使對象的內存泄露狀況,沒法被回收。
  5. 收集階段(Collected): 當垃圾回收器發現該對象已經處於「不可達階段」而且垃圾回收器已經對該對象的內存空間從新分配作好準備時,則對象進入了「收集階段」。若是該對象已經重寫了finalize()方法,則會去執行該方法的終端操做。
  6. 終結階段(Finalized): 當對象執行完finalize()方法後仍然處於不可達狀態時,則該對象進入終結階段。在該階段是等待垃圾回收器對該對象空間進行回收。
  7. 對象空間重分配階段(De-allocated): 垃圾回收器對該對象的所佔用的內存空間進行回收或者再分配了,則該對象完全消失了,稱之爲「對象空間從新分配階段」。
相關文章
相關標籤/搜索