HotSpot JVM基本原理(二)

最近學習了JVM的相關知識,主要是關於HosSpot的,這裏大致整理一下。

上次總結了一下JVM的結構和大致算法(地址:http://xlows.blog.51cto.com/5380484/1541823 )

這次接着總結


(1)根元素

wKiom1Py-NDikItXAAFqSZgdkhE262.jpg

由上圖可以發現,根元素包括很多:

1.類:被系統加載器加載的類,這些類存放在永久代,不能被垃圾回收器回收,至少jdk6和jdk7回收,但可以被類卸載器卸載;

2.線程:正在執行的線程對象;

3.局部變量中的棧當中的對象;

4.與java本地調用相關的局部和全局對象;

5.管程對象

6.java虛擬機進行垃圾回收階段時垃圾回收器對象


(2)標記過程

標記過程採用的算法爲DFS三色標記算法。

這裏大致介紹一下三色標記法:如果節點當中有3個顏色,白色,灰色和黑色,白色代表這個節點從來沒有被處理過,灰色代表正在被處理,黑色代表已經被處理。對應標記就是白色代表這個節點還沒被標記,灰色代表正在被標記還沒標記完,黑色代表已經標記完而且確確實實不能被回收。

下面舉個例子:

wKioL1Py-wjgs6uzAAC8u1_uxE4796.jpg

圖代表對象之間的引用關係,假設把1當做根對象,首先把1標記成灰色。

wKiom1Py-l2izy9wAADKoLmPNSE025.jpg

1引用的對象是4,下一步就是把4標記成灰色。

wKiom1Py-qHRrrvbAADM7Tt_NqQ998.jpg

現在有一個問題,4和1,2,5相連,那怎麼選擇呢?到底選擇1,2,還是5呢?很簡單,1已經被標記,所以不會選擇,而4會在2和5之間隨便選一個,2也可以,5也可以。那麼現在假設4選擇了2,把2標記成灰色。

wKiom1Py-wHw6pMWAADL_o-9Dbs576.jpg

2和4,5相關聯,但4已經被標記,所以只能選擇5。

wKioL1Py_H2zJaUTAADUy3VrPHo799.jpg

同理5會選擇3。

wKiom1Py-46iZJZ3AADVpkz3GDY647.jpg

此時3沒有與任何節點相連,所以下一步會把3標記成黑色代表3已經處理完成。

wKiom1Py_DfTgxg6AAD8hOsGpUI595.jpg

而後退出到5,此時可以發現5和3,2,4有關聯,代表可以通過5來標記3,也可以通過5來標記2或者4。但現在5和3這條線路已經被處理,5和2正在被處理(紅線代表正在被處理),但5和4還有一個標記,此時5會發現4也正在被處理,所以會退回來把,此時纔會把5標記成黑色。

wKioL1Py_gGgFbQbAAD8zqTqoII011.jpg

下一步就是處理2。

wKioL1Py_vfAPikyAAD6zYuattQ219.jpg

2和5、4相連,5已經被粗粒,他只能處理4,在處理4之前會把2標記成黑色,2在標記4,4可以和2,5,1關聯,2和5已經被處理,此時4會去探測一下,然後把4和5這條路徑給斷掉,然後把4標記成黑色。

wKioL1Py_1PQhE-tAADzwqVbadU414.jpg

最後在把1標記成黑色。

wKioL1Py_4nDIk6sAAD5T2vlZOg442.jpg

通過這種三色標記法,就可以通過根對象把與根對象相關聯的對象都找到處理。


(3)Shallow &&Retained Size

wKiom1Py_x7xKIFjAAExjrQyPRE057.jpg

在內存中申請一個結構體,通過SizeOf算出來的大小就是Shallow Size。

但是如果這個結構體有個指針,指向別的結構體,那麼通過這個結構體可以關聯到其他對象,這些對象可以是很大的,那麼這些結構體大小加起來的大小就是Retained Size。Retained Size代表垃圾回收器實際回收的大小。


wKiom1Py_-Pj_MgZAADPj0TCSNQ755.jpg

如上圖,R01的Retained Size就是S01+S02+S03,因爲04被根引用,所以不輸入01,依次類推,R02=S02+S03,R03=S03,R04=S04。

wKioL1PzAc2S2FASAADLOz2YOEI728.jpg

在看這幅圖,因爲04沒有被根引用到,所以R01=S01+S02+S03+S04,R02=S02+S03+S04,R03=S03,R04=S04。


(4)實現

wKiom1PzAWOTAf7TAAD2BG6Zx5s915.jpg

在介紹實現之前先要介紹幾個概念。

1.安全點:回收的時候必須有一個點,安全點。比如說一塊內存,正在申請,這個申請的過程應該保證是原子操作,不能在申請一半的時候GC把這個申請內存的動作打斷;或者有一個for循環,在循環的時候狀態可能在不斷改變,必須保證在循環過後才能回收。這些可能造成java虛擬機狀態改變的點叫做不安全點。那些可以讓java虛擬機狀態不在改變的點就叫做安全點。

線程達到安全點的方式有兩種,第一種是搶佔式,第二種是主動式。

什麼叫搶佔式呢?現在一個線程或者一個組件申請內存申請不到的時候,主線程去主動的操作子線程,讓它跑到安全點,或者強制讓它停止下來,也就是強迫你停下來進行垃圾回收。

第二種就是在垃圾回收的時候做一個標記,通過信號量的模式,它或者讓一個變量設置成標記量,設置成true或者false,設置爲true代表我要進行垃圾回收了,子線程在跑的過程中每隔一個階段會檢查這個標記位,如果這個標記位爲真的時候,那麼子線程跑到安全點的時候,主線程去執行垃圾回收,這就是主動式。

而垃圾回收的方式有3種,串行並行併發,具體將在下一篇博文中詳細介紹。



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