天天看點

淺談Java虛拟機JVM的垃圾回收機制

1. 什麼是垃圾

要回收垃圾,那麼垃圾是什麼?簡單的邏輯就是不會再被使用的記憶體對象呗。

2. 怎麼判斷不再被使用

2.1 引用計數法。統計有多少個引用指向記憶體對象,如果沒有引用指向記憶體對象,那麼該記憶體對象可以被當做垃圾。但是這邊有一個循環引用的問題,如一個方法内,建立了兩個新節點,它們之間互相引用,最終方法執行結束,方法内引用的對象應該被回收,但如果使用引用計數方案來處理,由于節點有被引用,會造成無法回收。

淺談Java虛拟機JVM的垃圾回收機制

2.2 可達性分析。如果一個對象和GC Roots之間沒有鍊路連接配接,那麼該對象可回收。但為了避免可達性分析過程中,其它使用者線程更改對象引用關系,會有GC停頓操作,也就是暫停Java所有工作線程。各個線程通過主動式查詢中斷标志位,然後決定是否中斷停在附近的安全點(方法調用、循環跳轉這些具有讓程式長時間執行的指令會産生安全點)。因為需要線程主動查詢中斷标志位,如果是那些睡眠或阻塞的線程,它們無法主動去查詢中斷标志位,是以它們會在進入睡眠或阻塞這些安全區域代碼時,辨別自己進入了安全區域。當虛拟機發起垃圾回收時不需要管進入安全區域的線程,如果這些線程在垃圾回收時結束了安全區域代碼,那麼會等待,直到JVM完成GC Roots枚舉。

2.3 GC Roots對象。可作為GC Roots對象的有四類:①虛拟機棧中局部變量表引用的對象;②類靜态屬性引用的對象;③方法區中常量引用的對象;④本地方法棧(帶有native修飾符的方法)中引用的對象。

3. 回收機制

确定了垃圾後,回收的機制:①如果“垃圾”對象沒有重寫finalize方法或者已經調用過finalize方法,那麼該“垃圾”對象直接被回收;②如果“垃圾”對象重寫了finalize方法并且還沒有調用過finalize方法,那麼會被放入F-Queue隊列中;稍後虛拟機會建立Finalize線程并執行finalize方法,如果對象要“拯救”自己,那麼隻要在finalize方法中再和GC Roots引用鍊上任何一個對象連接配接上即可。如果對象這時候還沒有逃脫,那麼它就真的被回收了。

4. 回收方法區(也叫永久代)的廢棄常量和無用的類

雖然虛拟機規範不要求對方法區進行垃圾回收,但還是可以對廢棄常量和無用類進行回收。無用類的判斷條件:①任何執行個體都被回收;②加載該類的ClassLoad也被回收;③該類對應的java.lang.Class對象沒有在任何地方被引用。