網(wǎng)站用gbk還是utf8惡意點擊軟件哪個好
一、并發(fā)標記與三色標記
問題:三色標記到底發(fā)生在什么階段,替代了什么。并發(fā)標記
1、并發(fā)標記( Concurrent Marking)
從 GC Root 開始對堆中對象進行可達性分析,遞歸掃描整個堆里的對象圖,找出要回收的對象,這階段耗時較長,但可與用戶程序并發(fā)執(zhí)行。當對象圖掃描完成以后 ,并發(fā)標記時有引用變動的對象 ,這些對象會漏標。
CMS和G1的并發(fā)標記階段使用的標記清除掃秒算法占用了太長中斷時間,所以用三色標記替換。
2、三色標記的概念(多線程)
在三色標記之前有一個算法叫Mark-And-Sweep(標記清除)。這個算法會給每一個對象設(shè)置一個標志位來記錄對象是否被使用。最開始標識位都是0,如果發(fā)現(xiàn)對象可達就會設(shè)置為1,一步步下去就會呈現(xiàn)一個類似樹狀的結(jié)果。等標記的步驟完成后,會將被標記的對象統(tǒng)一清理,再次把所有的標記位置設(shè)置成0方便下次清理。
標記清除最大的問題是GC執(zhí)行期間需要把整個程序完全暫停,不能異步進行GC操作。因為不同階段標記清除法的標志位0和1有不同的含義,那么新增的對象無論標記成什么都有可能意外刪除。對實時性要求高的系統(tǒng)來說,這種需要長時間掛起的標記清除算法是不可接受的。所以就需要一個算法來解決GC運行時程序長時間掛起的問題,那就是三色標記。
三色標記最大的好處就是異步,從而可以以中斷時間極少的代價或者完全沒有中斷來進行整個GC
三色標記把對象用三種顏色標記
- 黑色:根對象,或者這個對象及他的子對象都已經(jīng)被掃描了
- 灰色:本身已經(jīng)掃描了,子對象還沒掃描
- 白色:未被掃描的對象,如果掃描完所有的對象之后,最終白色的為不可達對象,既為垃圾
3、三色標記的問題
GC并發(fā)情況下會有漏標的問題
第一步:線程1完成所有的標記,線程2還處于半完成狀態(tài)
第二步:引用發(fā)成變化,B指向C變成A指向C
第三步:線程1、2都完成所有的標記,C對象是白色,被錯誤的回收
4、三色標記并發(fā)情況下漏標記解決方案(單線程,最終標記)
(1)cms的解決方案 incremental update 增量更新算法
CMS的三色標記發(fā)生并發(fā)標記和重新標記階段
當一個白色對象被一個黑色對象引用,將黑色對象重新標記為灰色,讓垃圾回收器重新掃描。增量更新,關(guān)注的是引用新增。
(2)G1中的解決方案 STAB (snapshot-at-the-beginning) 快照處理算法
剛開始做一個快照,當B指向C的引用消失的時候,就把這個引用推到GC的堆棧,保證C還能被GC掃描到,最重要的是要把這個引用推到GC的堆棧,是灰色對象B指向白色C的引用,如果一旦某一個引用消失掉了,會把它放到棧(GC方法運行時數(shù)據(jù)也是來自棧中),其實還是能找到它的,下回直接掃描他就行了,那樣白色就不會漏標。再次做一個快照,然后兩個快照進行對比,發(fā)現(xiàn)C不是垃圾,那就要對C單獨再做一次處理。
對應(yīng) G1 的垃圾回收過程中的:最終標記
對用戶線程做另外一個短暫的暫停,用于處理并發(fā)階段結(jié)束后仍遺留下來的最后那少量的SATB記錄(漏標對象)
(3)incremental update與STAB對比
為什么CMS不用快照,為什么G1不用增量
incremental Update算法關(guān)注引用的增加。(A-C的引用),如果增加了就變灰色,需要重新掃描
SATB算法是關(guān)注引用的刪除(B->C的引用)
G1 如果使用 Incremental Update 算法,因為變成灰色的成員還要重新掃,重新再來一遍,效率太低了。
所以 G1 在處理并發(fā)標記的過程比 CMS 效率要高,但是占內(nèi)存高,這個主要是解決漏標的算法決定的。
三、安全點與安全區(qū)域
1、安全點(不會發(fā)生引用的變化的代碼)
用戶線程暫停,GC 線程要開始工作,但是要確保用戶線程暫停的這行字節(jié)碼指令是不會導致引用關(guān)系的變化。
所以 JVM 會在字節(jié)碼指令中,選一些指令,作為“安全點”,比如方法調(diào)用、循環(huán)跳轉(zhuǎn)、異常跳轉(zhuǎn)等,一般是這些指令才會產(chǎn)生安全點。
為什么它叫安全點,GC 時要暫停業(yè)務(wù)線程,并不是搶占式中斷(立馬把業(yè)務(wù)線程中斷)而是主動式中斷。主動式中斷是設(shè)置一個標志,這個標志是中斷標志,各業(yè)務(wù)線程在運行過程中會不停的主動去輪詢這個標志,一旦發(fā)現(xiàn)中斷標志為 True,就會在自己最近的“安全點”上主動中斷掛起。
業(yè)務(wù)線程停止---安全點--->垃圾回收線程開始
業(yè)務(wù)線程主動式中斷,GC開始,STW業(yè)務(wù)線程, 業(yè)務(wù)線程輪訓標志S(0 OR 1),即GC開始標志,主動去中斷線程,跑到最近的安全點掛起。
2、安全區(qū)域
為什么需要安全區(qū)域?
要是業(yè)務(wù)線程都不執(zhí)行(業(yè)務(wù)線程處于 Sleep 或者是 Blocked 狀態(tài)),那么程序就沒辦法進入安全點,對于這種情況,就必須引入安全區(qū)域。
安全區(qū)域是指能夠確保在某一段代碼片段之中, 引用關(guān)系不會發(fā)生變化,因此,在這個區(qū)域中任意地方開始垃圾收集都是安全的。我們也可以把安全區(qū)城看作被擴展拉伸了的安全點。
當用戶線程執(zhí)行到安全區(qū)域里面的代碼時,首先會標識自己已經(jīng)進入了安全區(qū)域,這段時間里 JVM 要發(fā)起 GC 就不必去管這個線程了。
當線程要離開安全區(qū)域時,它要判斷 JVM 是否已經(jīng)完成了GC階段(根節(jié)點枚舉,或者其他 GC 中需要暫停用戶線程的階段)
1、如果完成了,那線程就當作沒事發(fā)生過,繼續(xù)執(zhí)行。
2、否則它就必須一直等待, 直到收到可以離開安全區(qū)域的信號為止。
四、低延遲的垃圾回收器
1、垃圾回收器的三項指標
傳統(tǒng)的垃圾回收器一般情況下內(nèi)存占用、吞吐量、延遲只能同時滿足兩個。但是現(xiàn)在的發(fā)展,延遲這項的目標越來越重要。所以就有低延遲的垃圾回收器。
2、Eplison(了解即可)
這個垃圾回收器不能進行垃圾回收,是一個“不干活”的垃圾回收器,由 RedHat 推出,它還要負責堆的管理與布局、對象的分配、與解釋器的協(xié)作、與編譯器的協(xié)作、與監(jiān)控子系統(tǒng)協(xié)作等職責,主要用于需要剝離垃圾收集器影響的性能測試和壓力測試。
3、ZGC(了解即可)
有類似于 G1 的 Region,但是沒有分代。
標志性的設(shè)計是染色指針 ColoredPointers(這個概念了解即可),染色指針有 4TB 的內(nèi)存限制,但是效率極高,它是一種將少量額外的信息存儲在指針上的技術(shù)。
它可以做到幾乎整個收集過程全程可并發(fā),短暫的 STW 也只與 GC Roots 大小相關(guān)而與堆空間內(nèi)存大小無關(guān),因此可以實現(xiàn)任何堆空間 STW 的時間小于十毫秒的目標。
JDK11 –ZGC(暫停時間不超過 10 毫秒,且不會隨著堆的增加而增加,TB 級別的堆回收)):
有色指針、加載屏障。JDK12 支持并發(fā)類卸載,進一步縮短暫停時間 JDK13(計劃于 2019 年 9 月)將最大堆大小從 4TB 增加到 16TB
4、Shenandoah(了解即可)
第一款非 Oracle 公司開發(fā)的垃圾回收器,有類似于 G1 的 Region,但是沒有分代。也用到了染色指針 ColoredPointers。效率沒有 ZGC 高,大概幾十毫秒的目標。
五、GC 參數(shù)和GC 日志詳解
1、GC 常用參數(shù)
-Xmn -Xms -Xmx –Xss 年輕代 最小堆 最大堆 ??臻g
-XX:+UseTLAB 使用 TLAB,默認打開
-XX:+PrintTLAB 打印 TLAB 的使用情況
-XX:TLABSize 設(shè)置 TLAB 大小
-XX:+DisableExplicitGC 啟用用于禁用對的調(diào)用處理的選項 System.gc()
-XX:+PrintGC 查看 GC 基本信息
-XX:+PrintGCDetails 查看 GC 詳細信息
-XX:+PrintHeapAtGC 每次一次 GC 后,都打印堆信息
-XX:+PrintGCTimeStamps 啟用在每個 GC 上打印時間戳的功能
-XX:+PrintGCApplicationConcurrentTime 打印應(yīng)用程序時間(低)
-XX:+PrintGCApplicationStoppedTime 打印暫停時長(低)
-XX:+PrintReferenceGC 記錄回收了多少種不同引用類型的引用(重要性低)
-verbose:class 類加載詳細過程
-XX:+PrintVMOptions 可在程序運行時,打印虛擬機接受到的命令行顯示參數(shù)
-XX:+PrintFlagsFinal -XX:+PrintFlagsInitial 打印所有的 JVM 參數(shù)、查看所有 JVM 參數(shù)啟動的初始值(必須會用)
-XX:MaxTenuringThreshold 升代年齡,最大值 15, 并行(吞吐量)收集器的默認值為 15,而 CMS 收集器的默認值為 6。
2、Parallel 常用參數(shù)
-XX:SurvivorRatio 設(shè)置伊甸園空間大小與幸存者空間大小之間的比率。默認情況下,此選項設(shè)置為 8
-XX:PreTenureSizeThreshold 大對象到底多大,大于這個值的參數(shù)直接在老年代分配
-XX:MaxTenuringThreshold 升代年齡,最大值 15, 并行(吞吐量)收集器的默認值為 15,而 CMS 收集器的默認值為 6。
-XX:+ParallelGCThreads 并行收集器的線程數(shù),同樣適用于 CMS,一般設(shè)為和 CPU 核數(shù)相同
-XX:+UseAdaptiveSizePolicy 自動選擇各區(qū)大小比例
3、CMS 常用參數(shù)
-XX:+UseConcMarkSweepGC 啟用 CMS 垃圾回收器
-XX:+ParallelGCThreads 并行收集器的線程數(shù),同樣適用于CMS,一般設(shè)為和 CPU 核數(shù)相同
-XX:CMSInitiatingOccupancyFraction 使用多少比例的老年代后開始 CMS 收集,默認是 68%(近似值),如果頻繁發(fā)生 SerialOld 卡頓,應(yīng)該調(diào)小,(頻繁 CMS 回收)
-XX:+UseCMSCompactAtFullCollection 在 FGC 時進行壓縮
-XX:CMSFullGCsBeforeCompaction 多少次 FGC 之后進行壓縮
-XX:+CMSClassUnloadingEnabled 使用并發(fā)標記掃描(CMS)垃圾收集器時,啟用類卸載。默認情況下啟用此選項。
-XX:CMSInitiatingPermOccupancyFraction 達到什么比例時進行 Perm 回收,JDK 8 中不推薦使用此選項,不能替代。
-XX:GCTimeRatio 設(shè)置 GC 時間占用程序運行時間的百分比(不推薦使用)
-XX:MaxGCPauseMillis 停頓時間,是一個建議時間,GC 會嘗試用各種手段達到這個時間,比如減小年輕代
4、G1 常用參數(shù)
-XX:+UseG1GC 啟用 CMS 垃圾收集器
-XX:MaxGCPauseMillis 設(shè)置最大 GC 暫停時間的目標(以毫秒為單位)。這是一個軟目標,并且 JVM 將盡最大的努力(G1 會嘗試調(diào)整 Young 區(qū)的塊數(shù)來)來實
現(xiàn)它。默認情況下,沒有最大暫停時間值。
-XX:GCPauseIntervalMillis GC 的間隔時間
-XX:+G1HeapRegionSize 分區(qū)大小,建議逐漸增大該值,1 2 4 8 16 32。隨著 size 增加,垃圾的存活時間更長,GC 間隔更長,但每次 GC 的時間也會更長
-XX:G1NewSizePercent 新生代最小比例,默認為 5%
-XX:G1MaxNewSizePercent 新生代最大比例,默認為 60%
-XX:GCTimeRatioGC 時間建議比例,G1 會根據(jù)這個值調(diào)整堆空間
-XX:ConcGCThreads 線程數(shù)量
-XX:InitiatingHeapOccupancyPercent 啟動 G1 的堆空間占用比例,根據(jù)整個堆的占用而觸發(fā)并發(fā) GC 周期