JVM 進行時

上一篇中 我講述了下關於JVM的基礎內容,這次呢,主要從JVM的內部存儲結構出發....

即:主要了解想堆(Heap)的內存模型

一塊是非堆區,一塊是堆區。
堆區分爲兩大塊,一個是Old區,一個是Young區。
Young區分爲兩大塊,一個是Survivor區(S0+S1),一塊是Eden區。 Eden:S0:S1=8:1:1
S0和S1一樣大,也可以叫From和To。

那麼對於這樣內存來說,一般對象和數組的創建會在堆中分配內存空間,但是堆中有這麼多的區域,具體怎麼存儲呢??

對象創建所在區域

一般情況下,新創建的對象都會被分配到Eden區,一些特殊的大的對象會直接分配到Old區

   在Eden 的空間有限,在達到空間的臨界值時,就會需要對內存進行垃圾回收GC(即:Garbage Collect)。這樣的GC我們稱之爲Minor GC,Minor GC指得是Young區的GC,但是並不是每次GC都會全部回收掉,也有些對象會存活下來。這些存活對象會被賦值出來存在S區(Survivor區)。然後在清除Eden中的對象,這樣也保證了Eden的區域相對來說比較連續些。

Survivor區詳解

Survivor區分爲兩塊S0和S1,也會叫做(from 和 to),佔比是一樣(1:1),這2個區域在同一個時間必須要有一個是空的,這樣利於在進行GC時

例如:一開始只有Eden區和S0中有對象,S1中是空的。
此時進行一次GC操作,S0區中對象的年齡就會+1,我們知道Eden區中所有存活的對象會被複制到S1區,
From區中還能存活的對象會有兩個去處。
若對象年齡達到之前設置好的年齡閾值,此時對象會被移動到Old區,沒有達到閾值的對象會被複制到S1區。
此時Eden區和S0區已經被清空(被GC的對象肯定沒了,沒有被GC的對象都有了各自的去處)。
這時候S0和S1交換角色,之前的S0變成了S1,之前的S1變成了S0。
也就是說無論如何都要保證Survivor區域中有個區域是空的。
Minor GC會一直重複這樣的過程,知道S1區被填滿,然後會將所有對象複製到老年代中。

當然這麼操作的話,那麼必然Old區也會達到內存的一個臨界值,肯定也是會進行GC的,這樣的old 的GC叫做:Major GC

Minor GC:新生代
Major GC:老年代
Full GC:新生代+老年代

爲什麼需要Survivor區?只有Eden不行嗎?

      顧名思義,Survivor(存活),大多數的時候 因爲程序線程運行的時候,會產生對象,這種對象一般都是朝生夕死的,存活時間比較短,如果都存在Eden區的話,那麼很快內存就會滿,這樣的話GC(Minor GC)的次數就要增加,GC多的話,那麼Old區也就會加速填滿,這樣的話Old區的話GC(Major GC)也會隨着增加,這樣就可以看做觸發了Full GC。老年代的內存空間遠大於新生代,進行一次Full GC消耗的時間比Minor GC長得多。GC的時間加長了的話,這樣客戶端的響應時間拉長。

所以說Survivor區存在的目的主要還是爲了減少GC的次數,從而也減少了FULL GC。加速了響應時間。

爲什麼需要兩個Survivor區?

  分2個,而且2個的佔比是(1:1),很明顯就是爲了解決空間的碎片化。如果一個S區的話,例如:一旦Eden 區滿了,觸發了GC,那麼把存活的對象存入S區。下一次的時候有GC了,那麼Eden和Survivor各有一些存活對象,如果此時把Eden區的
存活對象硬放到Survivor區,很明顯這兩部分對象所佔有的內存是不連續的,也就導致了內存碎片化。

接下來介紹一個jdk (jvisualvm)自帶的一款查看分析內存的工具

https://visualvm.github.io/pluginscenters.html --->選擇對應版本鏈接--->Tools--->Visual GC

啓動對應的項目,即可看到對的堆內存的分佈 如下:

通過這個工具,可以自己在idea裏面創建一個類(如:死循環,創建類對象等),自己手動製造“車禍現場”.....

未完待續,如有敘述不對的地方,各位看官大佬,多多指點...

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章