深入理解Java虛擬機(四)之垃圾回收相關概念

System.gc()的理解

  • 在默認情況下,通過System. gc()或者Runtime . getRuntime () .gc()的調用,會顯式觸發FullGC,同時對老年代和新生代進行回收,嘗試釋放被丟棄對象佔用的內存。
  • 然而System. gc()調用附帶一個免責聲明,無法保證對垃圾收集器的調用。
  • JVM實現者可以通過System. gc ()調用來決定JVM的GC行爲。而一般情況下,垃圾回收應該是自動進行的,無須手動觸發,否則就太過於麻煩了。在一些特殊情況下,如我們正在編寫一個性能基準,我們可以在運行之間調用System.gc()。

用戶線程的暫停:Stop-The-World(STW)

垃圾回收工作是在垃圾回收線程中執行的,在很多情況下,執行垃圾回收工作,或是執行垃圾回收其中 某一步驟時需要暫停用戶線程,也就是Stop-The-World(STW)。

  • 垃圾回收首先是要經過標記的。對象被標記後就會根據不同的區域採用不同的收集方法。
  • 垃圾回收線程標記好對象時,用戶線程在併發執行時,可能會將該對象重新加入“引用鏈”,垃圾回收時就會回收這個不該回收的對象,出現問題。
  • 在類加載完成的時候,HotSpot就把對象內什麼偏移量上是什麼類型的數據計算出來,在JIT編譯過程中,也會在特定的位置記錄下棧和寄存器中哪些位置是引用。這樣,GC在掃描時就可以直接得知這些信息了。這些特定的位置稱爲安全點(Safepoint)。
  • 程序執行時並非在所有地方都能停頓下來開始GC,只有在到達安全點時才能暫停。
  • GC發生時讓所有線程暫停,即讓所有線程“跑”到最近的安全點上再停頓下來,有兩種方案可供選擇:
  1. 搶先式中斷(PreemptiveSuspension):不需要線程的執行代碼主動去配合,在GC發生
    時,首先把所有線程全部中斷,如果發現有線程中斷的地方不在安全點上,就恢復線程,讓
    它“跑”到安全點上。現在幾乎沒有虛擬機實現採用搶先式中斷來暫停線程從而響應GC事件。
  2. 主動式中斷(Voluntary Suspension):是當GC需要中斷線程的時候,不直接對線程操作,僅僅簡單地設置一個標誌,各個線程執行時主動去輪詢這個標誌,發現中斷標誌爲真時就自己中斷掛起。輪詢標誌的地方和安全點是重合的,另外再加上創建對象需要分配內存的地方。

在垃圾收集器的學習中,有兩個概念需要先說明:

  • 並行(Parallel) : 指多條垃圾收集線程並行工作,用戶線程仍處於等待狀態。
  • 併發(Concurrent) : 指用戶線程與垃圾收集線程同時執行(不一定並行,可能會交替執行),用戶程序繼續運行,而垃圾收集程序在另外一個CPU上。

安全點與安全區域

安全點:

程序執行時並非在所有地方都能停頓下來開始GC, 只有在特定的位置才能停頓下來開始GC,這些位置稱爲“安全點(Safepoint) ”.

SafePoint的選擇很重要,如果太少可能導致GC等待的時間太長,如果太頻繁可能導致運行時的性能問題。大部分指令的執行時間都非常短暫,通常會根據“是否具有讓程序長時間執行的特徵”爲標準。比如:選擇些執行時間較長的指令作爲Safe Point, 如方法調用、循環跳轉和異常跳轉等。

如何在GC發生時,檢查所有線程都跑到最近的安全點停頓下來呢?

  • 搶先式中斷:(目前沒有虛擬機採用了)
    首先中斷所有線程。如果還有線程不在安全點,就恢復線程,讓線程跑到安全點。
  • 主動式中斷:
    設置一箇中斷標誌,各個線程運行到Safe Point的時 候主動輪詢這個標誌,如果中斷標誌爲真,則將自己進行中斷掛起。

安全區域

Safepoint機制保證了程序執行時,在不太長的時間內就會遇到可進入GC的Safepoint。但是,程序“不執行”的時候呢?例如線程處於Sleep
狀態或Blocked 狀態這時候線程無法響應JVM的中斷請求“走”到安全點去中斷掛起:JVM也不太可能等待線程被喚醒。對於這種情況,就需要安全區域(Safe Region)來解決。

安全區域是指在一段代碼片段中,對象的引用關係不會發生變化,在這個區域中的任何位置開始GC都是安全的。我們也可以把Safe Region看做是被擴展了的Safepoint。

引用

強引用

指在程序代碼之中普遍存在的,類似Object obj=new Object()這類的引用,只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象。

軟引用(內存不足即回收)

用來描述一些還有用但並非必需的對象。對於軟引用關聯着的對象,在系統將要發生內存溢出異常之前,將會把這些對象列進回收範圍之中進行第二次回收。如果這次回收還沒有足夠的內存,纔會拋出內存溢出異常。在JDK 1.2之後,提供了SoftReference類來實現軟引用。

弱引用(發現即回收)

用來描述非必需對象的,但是它的強度比軟引用更弱一些,被弱引用關聯的對象只能生存到下一次垃圾收集發生之前。當垃圾收集器工作時,無論當前內存是否足夠,都會回收掉只被弱引用關聯的對象。在JDK 1.2之後,提供了WeakReference類來實現弱引用。

虛引用

也稱爲幽靈引用或者幻影引用,它是最弱的一種引用關係。一個對象是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用來取得一個對象實例。爲一個對象設置虛引用(PhantomReference)關聯的唯一目的就是能在這個對象被收集器回收時收到一個系統通知。

Java的語言類型

Java屬於混合型語言(Mixed Mode),即有編譯期編譯的過程,也存在運行期解釋和編譯的過程。

在編譯期通過javac編譯器編譯java文件,運行期通過解釋器(Interpreter)和即時編譯器(Just In Time
Compiler,JIT編譯器)配合完成解釋、編譯工作。

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