1. 程式人生 > >JVM記憶體回收區域+物件存活的判斷+引用型別+垃圾回收執行緒

JVM記憶體回收區域+物件存活的判斷+引用型別+垃圾回收執行緒


此文已由作者趙計剛薪授權網易雲社群釋出。

歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。


注意:本文主要參考自《深入理解Java虛擬機器(第二版)》

說明:檢視本文之前,推薦先知道JVM記憶體結構,見《第一章 JVM記憶體結構

1、記憶體回收的區域

  • 堆:這是GC的主要區域

  • 方法區:回收兩樣東西

    • 無用的類

    • 廢棄的常量

  • 棧和PC暫存器是執行緒私有區域,不發生GC

 

2、怎樣判斷物件是否存活

垃圾回收:回收掉死亡物件所佔的記憶體。判斷物件是否死亡,有兩種方式:

  • 引用計數法

    • 每次為物件賦值時,都要進行計數器值的增減,消耗較大

    • 對於A、B相互引用這種情況處理不了(這一點是不用的主要原因)

    • 原理:給物件新增一個引用計數器,每當有一個地方引用它時,計數器值+1;引用失效時,計數器值-1

    • 實際中不用,不用的兩個原因

  • 可達性分析(跟蹤收集)

    • 原理:從根集合(GC Roots)開始向下掃描,根集合中的節點可以到達的節點就是存活節點,根集合中的節點到達不了的節點就是將要被回收的死亡節點,如下圖中的A/B/C是存活節點,D/E是死亡節點:



    • Java棧中的物件引用(存在於區域性變量表中,注意:區域性變量表中存放的是基本資料型別和物件引用)

    • 方法區中:常量+靜態(static)變數

    • 傳到本地方法中,還沒有被本地方法釋放的物件引用

    • 這是垃圾回收最多考慮的地方,所以有時,我們也會將死亡物件稱為"沒有引用指向的物件"

    • 根集合中的節點包括:簡單來講,就是全域性性的引用(常量和靜態屬性)和棧引用(下邊第一、三)

 

3、3種引用型別

  • 強引用(Strong Reference):A a = new A();//a是強引用

  • 軟引用(Soft Reference):當記憶體不足時,釋放軟引用所引用的物件;當記憶體足夠時,就是一個普通物件(強引用)

  • 弱引用(Weak Reference):弱引用物件只能存活到下一次垃圾回收之前,一旦發生垃圾回收,立刻被回收掉

 

4、方法區的回收

  • 廢棄常量:例如,沒有任何一個引用指向常量池中的"abc"字串,則"abc"字串被回收

  • 無用的類:滿足以下三個條件

    • Java堆中不存在該類的任何例項

    • 載入該類的ClassLoader被回收

    • 該類的Class物件沒有在任何地方被引用

注意:

  • 在實際開發中,儘量不用JSP去做前端,而是用velocity、freemarker這樣的模板引擎去做

  • 與類相關常用的三個引數:

    • -XX:+PrintClassHistogram:輸出類統計狀態

    • -XX:-TraceClassLoading:列印類載入資訊

    • -XX:-TraceClassUnloading:列印類解除安裝資訊

 

5、垃圾回收執行緒

系統的垃圾回收是由垃圾回收執行緒來檢測操作的,該執行緒是一個後臺執行緒(daemon thread)。

5.1、後臺執行緒與我們使用的前臺執行緒而言,有一個特點:當JVM中的前臺執行緒數量為0時,後臺執行緒自動消亡。可以這樣講,後臺執行緒依託於前臺執行緒而存在。

5.2、垃圾回收執行緒為什麼要設定成為後臺執行緒呢?

我們想一下,當前臺一個執行緒都沒有時,垃圾還會有嗎?或者說垃圾回收還有必要嗎?答案是沒有必要,所以此時垃圾回收執行緒也就失去了存活的意義。

所以可以這樣講,將一個執行緒是否設定為後臺執行緒,就看這條執行緒在沒有其他執行緒存在的情況下,是否還有存活的意義。

例如,在我們使用Apache mina2做RPC時,我們在訊息的接收端直接開啟一個後臺執行緒啟動服務來接受訊息傳送端發來的訊息事件請求就可以。試著去想,如果在整個JVM中只有當前的這一個後臺執行緒了,那麼這個執行緒還有必要存活下來嗎?當然沒有必要,因為訊息永遠都不會再發送了(前臺執行緒都沒了)

 

免費領取驗證碼、內容安全、簡訊傳送、直播點播體驗包及雲伺服器等套餐

更多網易技術、產品、運營經驗分享請點選


相關文章:
【推薦】 為什麼 kubernetes 天然適合微服務
【推薦】 網易考拉規則引擎平臺架構設計與實踐
【推薦】 微服務化的基石——持續整合