美麗又短暫的假期竟然這麼快就結束了,學習的小車輪繼續的滾起來吧算法
垃圾回收器爲何必需要停頓下?
在垃圾收集器在獲取根節點這一步時必須暫停用戶線程的也就是咱們常說的STW,目前可達性分析算法耗時最長的查找引用鏈的過程已經能夠作到和用戶線程一塊兒併發,但根節點枚舉的獲取還必須是要在一個能保證一致性的快照中才能進行。安全
這裏說的一致性就是根節點枚舉分析期間執行子系統看起來就像被凍結在某個時間點上,不會出現一邊分析,根節點的對象引用關係還在不斷的變化的狀況。這也是致使垃圾收集過程必須停頓全部用戶線程的其中一個重要緣由,即使是號稱停頓時間可控的CMS、G一、ZGC等,跟節點分析時也是必需要停頓的。數據結構
GC Roots
都知道JVM內對象存活斷定通常用可達性分析算法,也就是說在HotSpot 使用裏面維護了不少根節點(GC Roots)。多線程
GC Roots種類:併發
-
靜態變量引用的對象高併發
-
常量引用的對象學習
-
棧針本地變量表引用的對象url
-
JNDI 引用的對象.net
什麼是OopMap ?
目前主流JVM垃圾收集,在當用戶線程停頓下後實際上是不須要一個不漏的檢查完全部的執行上下文和全局引用位置的。在HotSpot中是使用一組成爲OopMap的數據結構來達到這個目的的。線程
當類加載動做完成時,HotSpot就會將對象內的類型、偏移量等數據計算出來,這時在垃圾收集器掃描的時候就能夠直接獲得這些信息了,並不須要一個不漏的從GC Roots開始查找。
藉助於OopMap,虛擬機能夠快速枚舉GC Root引用,這就是典型的以空間換時間。但致使引用關係變化很是多,又不能生成過多的OopMap從而致使存儲資源的浪費,因此又出現了安全點和安全區域。
什麼是安全點?
在OopMap的幫助下,能夠快速的完成GC Roots數據掃描,但能夠致使引用關係變化的可能太多了,也就是說致使OopMap內容變化的指令很是多,不可能每次變化都生成對應的OopMap。
因此,在某個特定的位置來記錄關係信息到OopMap,這些位置就被稱爲安全點。其實也就是在代碼執行到達指定的位置纔可以暫停進行信息收集。
舉例Serial 收集器(其餘收集器也差很少):
- 單線程收集器,收集的時候會暫停全部用戶線程(簡稱STW)
- 客戶端模式下默認收集器
- 簡單高效,是全部收集器中額外內存消耗最小的
安全點的選定:具備讓程序長時間執行的特徵,例如方法調用、循環跳轉、異常跳轉等。
怎麼到達安全點?
在實際狀況下,是不可能在發生垃圾收集的時候全部的線程都正好在安全點,因此就須要線程都跑到最近的安全點而後停頓下來。
有兩種方案:
搶先試中斷(Preemptive Suspension):(如今幾乎沒有用這種的了)
不須要線程的執行代碼主動配合,在垃圾收集發生時,系統首先把全部用戶線程所有中斷,若是發現有用戶線程中斷的地方再也不安全點上,就恢復這條線程執行,讓它一會再從新中斷,直到到達安全點。
主動式中斷(Voluntary Suspension):
在垃圾收集須要中斷線程的時候,不直接對線程操做,僅簡單的設置一個標誌位,各個線程執行過程時會不停的主動去輪詢這個標誌,一旦發現中斷標誌爲true時就在本身最近的安全點上主動掛起。
什麼是安全區域?
安全點彷佛解決了讓虛擬機內部線程主動停頓,整個虛擬機進入垃圾回收狀態的問題。但在實際狀況下,若是線程處於sleep 或Blocked狀態的話是沒有分配CPU時間的,這時線程是沒法響應虛擬機的中斷請求,不能再走到安全點進行掛起,而虛擬機也不能持續的等待線程被從新激活分配CPU。這種狀況,就必須引入安全區域(Safe Region)來解決問題了。
安全區域,能夠看做是安全點的擴展。指的是可以確保在某一段代碼片斷中,引用關係不會發生變化,在這個區域中任意地方開始來及手機都是安全的。
安全區域內發生了什麼?
當線程執行到安全區域裏的代碼時,會先標識本身進入了安全區域,若是這時段裏進行了垃圾收集虛擬機就沒必要去管這些已經標識過的線程了
當線程離開安全區域時,它要檢查下虛擬機是否完成了根節點的掃描或者垃圾收集過程當中須要停頓的階段。若是完成了,那線程就會繼續執行。不然就必須一直等待,直到收到能夠離開安全區域的信號。
結尾
看完這些,你能回答下面的問題嗎!
垃圾收集器爲何必需要停頓下?
安全點和安全區域的區別?
往期推薦