安全點與安全區域詳解

對於以前GC垃圾收集器的學習回憶【http://www.javashuo.com/article/p-xcmnozpx-ge.html】一下都有哪些垃圾收集器:html

接下來則會對CMS這種超級複雜的一個垃圾回收器進行一個學習,相比serial收集器仍是parallel收集器,CMS這種收集器不管是在處理的階段上,仍是在它的實現的複雜性上,都遠遠的要超過咱們以前所接觸過的各類各樣的其它垃圾回收器,CMS的複雜性體現是多方面的:首先是它的源代碼是很是複雜,在新版本的JDK中已經將CMS這個垃圾回收器標記爲@Deprecated的了, 對於爲啥會將它標記爲@Deprecated在國外twtter上有這麼一個「段子」,緣由是因爲當時編寫CMS的人已經離職了,離職以後新接手的人是不管如何也看不懂CMS的C++源代碼,因此從側面也能反應CMS垃圾收集器是有多麼的複雜。 對於咱們而言無論代碼實現上是如何的複雜,首先得從原理上去理解CMS這種垃圾回收器究竟是作什麼事情的?到底有什麼特色爲啥它這麼複雜?爲啥如此複雜的回收器還能普遍的存在於各個版本的JDK當中?像我們實現用的JDK8也是能夠正常去使用這個CMS回收器的,只要在JVM的啓動參數上加上相應CMS回收器也能正常使用了。CMS是隸屬於老年代的垃圾回收器,而新生代基本上都會採用複製算法,不管是serial收集器仍是parallel收集器,因此在新生代中就會存在一個Eden區域和兩個Survivor【From、To】區域,而在老年代中通常是會使用標記-清除【mark-sweep】或標記-整理算法【mark-compact】,因此接下來會來理解CMS垃圾回收器的基本原理,而首先對它的理論的瞭解是助於咱們能瞭解其原理的基礎,因此。。直接硬着頭皮來了解理論:web

枚舉根節點:算法

當執行系統停頓下來以後,並不須要一個不漏地檢查完全部執行上下文和全局的引用位置,虛擬機應當是有辦法直接得知哪些地方存放着對象引用。在HotSpot的實現中,是使用一組稱爲OopMap的數據結構來達到這個目的的。安全

 

安全點:數據結構

關於這個概念其實在以前理論的學習中是已經提到過的,回憶一下:學習

因此接下來了解一下這個概念。spa

  • 在OopMap的協助下,HotSpot能夠快速且準確地完成GC Roots枚舉,但一個很現實的問題隨之而來:可能致使引用關係變化,或者說OopMap內容變化的指令很是多,若是爲每一條指令都生成對應的OopMap,那將會須要大量的額外空間,這樣GC的空間成本將會變得更高。
  • 實際上,HotSpot並無爲每條指令都生成OopMap,而只是在「特定的位置」記錄了這些信息,這些位置稱爲安全點(Safepoint) ,既程序執行時並不是在全部地方都能停頓下來開始GC,只有在達到安全點時才能暫停。這裏解釋一下:當JVM遇到空間不夠的時候會執行垃圾回收,但並非在系統的任什麼時候刻均可以執行垃圾回收,必需要等到程序執行到一個稱之爲安全點這樣的一個位置上才能夠進行GC。
  • Safepoint的選定既不可能太少以致於讓GC等待時間太長,也不能過於頻繁以致於過度增大運行時的負載。因此,安全點的選定基本上是以「是否具備讓程序長時間執行的特徵」爲標準進行選定的----由於每條指令執行的時間很是短暫,程序不太可能由於指令流長度太長這個緣由而過長時間執行,「長時間執行」的最明顯特徵就是指令序列複用,例如方法調用、循環跳轉、異常跳轉等,因此具備這些功能的指令纔會產生Safepoint。
  • 對於Safepoint,另外一個須要考慮的問題是如何在GC發生時讓全部線程(這裏不包括執行JNI調用的線程)都「跑」到最近的安全點上再停頓下來:搶佔式中斷(Preemptive Suspension)和主動式中斷(Voluntary Suspension)。
  • 搶佔式中斷:它不須要線程的執行代碼主動去配合,在GC發生時,首先把全部線程所有中斷,若是有線程中斷的地方不在安全點上,就恢復線程,讓它「跑」到安全點上。
  • 主動式中斷:當GC須要中斷線程的時候,不直接對線程操做,僅僅簡單地設置一個標誌,各個線程執行時主動去輪循這個標誌,發現中斷標誌爲真時就本身中斷掛起。輪循標誌的地方和安全點是重合的【這個很關鍵,這樣經過標誌來中斷恰好是在安全點上發生的】,另外再加上建立對象須要分配內存的地方。注意:如今幾乎沒有虛擬機採用搶佔式中斷來暫停線程從而響應GC事件。

安全區域:線程

  • 在使用Safepoint彷佛已經完美地解決了如何進入GC的問題,但實際上狀況卻並不必定。Safepoint機制保證了程序執行時,在不太長的時間內就會遇到可進入GC的Safepoint。但若是程序在「不執行」的時候呢?所謂程序不執行就是沒有分配CPU時間,典型的例子就是處於Sleep狀態或者Blocked狀態,這時候線程沒法響應JVM的中斷請求,JVM也顯示不太可能等待線程從新分配CPU時間。對於這種狀況,就須要安全區域(SafeRegin)來解決了。
  • 在線程執行到Safe Region中的代碼時,首先標識本身已經進入了Safe Region,那樣,當在這段時間裏JVM要發起GC時,就不用管標識本身爲Safe Region狀態的線程了,在線程要離開Safe Region時,它要檢查系統是否已經完成了根節點枚舉(或者是整個GC過程),若是完成了,那線程就繼續執行,不然它就必須等待直到收到能夠安全離開Safe Region的信號爲止。

以上的理論確實是有點頭大,木關係,以後慢慢會經過實踐再來理解的~~htm

相關文章
相關標籤/搜索