1. 程式人生 > >jvm垃圾收集機制詳解(下)

jvm垃圾收集機制詳解(下)

上一篇傳送門:jvm垃圾收集機制詳解(中)

三、HotSpot虛擬機器的垃圾收集實現

根據之前的講解,java分析物件是否需要被回收是通過對物件的可達性分析來確定的,而可達性分析是通過識別物件是否連結到GC Roots物件決定的。那麼很顯然,我們需要通過遍歷所有的GC Roots節點,然後剩下的沒有連結到GC Roots節點的物件就是我們要回收的物件的。那麼問題就來了,GC Roots節點那麼多,還有重複的GC Roots節點連結到同一物件,那麼難道說每次我們進行垃圾收集的時候都要耗費大量時間去遍歷一遍嗎?

HotSpot虛擬機器是我們現在使用的主流java虛擬機器,讓我們看看它是如何做的:

1.遍歷GC Roots時要停頓

我們先不談如何去解決遍歷耗時間的問題,先來思考一個問題:在遍歷進行的時候物件是否還在進行更改或者其它操作?

答案是顯而易見的,這就好像你的女朋友在你屋子裡幫你掃地,你需要停下手裡的工作給她讓地方,而且不能女朋友一邊在掃地,你一邊往地上去扔垃圾,那樣恐怕就要挨大嘴巴子了。物件也是這樣,每當進行垃圾回收的時候都要停下,停下的時間很短,這段時間裡儲存一個快照來儲存自身的狀態資訊。

2.使用OopMap儲存資訊

為了解決每次垃圾回收都要遍歷去獲得回收物件位置的問題,jvm使用了一種叫做OopMap的資料結構來儲存物件的引用,在類載入完成的時候,jvm就將物件儲存位置偏移量什麼的計算出來,儲存到OopMap中,當需要垃圾回收的時候直接就可以精確“制導”,一下子就能找到物件的位置

3.安全點

那麼,我們應該在什麼時候停止執行呢?是一得到垃圾回收的指令就馬上去停止嗎?
當然不是,那樣估計就該出大亂子了,我們應該選取一個安全的狀態去停止然後根據OopMap去更改OopMap中的資訊或者進行垃圾回收,這種安全的狀態叫做“安全點”,也就是你和你的女朋友有個約定,當我把手裡的工作進行到百分之多少的時候我就停下來,你就來打掃衛生,我不會給你搗亂。
程式不是在所有的地方都能停止下來進行GC(垃圾回收),而是必須要當執行到安全點的時候才能停下來進行垃圾回收,那麼問題又來了,垃圾回收是一個執行緒,當我們現在有多個執行緒的時候,每個執行緒執行的程式都有它們自己分別的安全點,我們要等待所有執行緒都執行到安全點才能停下來進行垃圾回收,由於每個執行緒的安全點都在程式的不同位置,會不會造成執行緒1執行到安全點時執行緒2還沒有到安全點,導致執行緒1必須停在當前位置等待執行緒2執行到安全點呢?

針對這種問題,我們必須為安全點做一些辯解了,安全點在一個程式中有很多很多,而且,安全點的選擇也是有講究的,jvm會依照“既不能太少以至於當GC等待時間過長,也不能太多增加程式執行時的負荷”來選取安全點,安全點是以“是否具有讓程式長時間執行的特徵”為標準選定的。而且因為每條指令的執行時間都非常短暫,因此剛剛我們擔心的問題根本不會出現。

4.安全區

現在我們有這樣一種情況:一個執行緒處於sleep狀態或者阻塞狀態,現在這個執行緒沒法執行自己到安全點,如果恰好在這時需要GC,那麼是不是就意味著GC永遠也沒法進行垃圾回收成功了?

當然不是,對於一些程式沒有分配cpu時間片來執行的情況(例如上面說的sleep和阻塞情況),在這種情況下,程式已經沒法再去給GC搗亂,沒法去更改自身的資訊了,還要個卵的安全點?也就是說,現在女朋友給你下了迷藥,你已經趴在桌子上睡死過去了,那麼女朋友當然就可以不用顧及你,直接開始打掃衛生了。我們把這種情況下的程式稱為處於安全區中的程式,當程式進入到了安全區的時候,會標記自己已經進入了安全區,當這段時間要進行GC的時候,GC不會去管處於安全區中的執行緒程式,當執行緒要離開的時候,必須檢查GC是否已經完成了遍歷GC Roots或者整個GC過程,如果完成了,執行緒就可以順利退出安全區,否則就必須等待完成才可以出去。

至此,我們就完成了對垃圾回收的講解,還有很多沒講的是關於各種不同垃圾回收器的具體區別和優缺點,這個就要讀者朋友們自己慢慢學習了。

我也好希望能有個幫我攬走所有家務活的女朋友,不過倒是不希望她為了打掃房間給我下迷藥。。。

  • 參考書籍:《深入理解Java虛擬機器》