Java常见GC算法_垃圾收集器及内存分配_G1垃圾收集器
常見GC算法
- 引用計(jì)數(shù)法: 每個(gè)對(duì)象都有一個(gè)計(jì)數(shù)器, 對(duì)象被引用一次, 計(jì)數(shù)器+1, 當(dāng)對(duì)象引用失敗一次. 計(jì)數(shù)器-1, 當(dāng)對(duì)象計(jì)數(shù)器等于0, 說明對(duì)象沒有被應(yīng)用, 就可GC
- 標(biāo)記清除: 先標(biāo)記( 從root進(jìn)行可達(dá)性分析, 標(biāo)記被引用的對(duì)象), 再清除(清除那些沒被引用的對(duì)象)
- 標(biāo)記壓縮: 標(biāo)記需要回收的區(qū)域, 進(jìn)行回收, 將碎片化的空間進(jìn)行壓縮
- 復(fù)制算法: 將空間一分為二(只使用其中一塊空間進(jìn)行存儲(chǔ)), 進(jìn)行清除的時(shí)候, 將存活對(duì)象復(fù)制到另外一塊空間, 原本的空間全部清除, 解決移動(dòng)內(nèi)存問題
復(fù)制算法在JVM年輕代的應(yīng)用
1. GC開始前, 對(duì)象分布于Eden, s0區(qū), s1區(qū)為空 2. GC開始, Eden中的存活對(duì)象全部復(fù)制到s1中, s0區(qū)中存活對(duì)象根據(jù)他們的年齡值決定去向使用-XX:MaxTenuringThreshold設(shè)置年齡閾值, 超過該閾值, s0中對(duì)象移到老年代, 未達(dá)到, 對(duì)象則移動(dòng)到s1中 3. GC完成, 清空Eden, s0區(qū)域, s0與s1交換角色, 重復(fù)步驟1, 直到"s1"被填滿, 然后將"s1"中對(duì)象全部移到老年代中 優(yōu): 垃圾對(duì)象較多時(shí), 效率高, 無碎片化 缺: 垃圾較少, 不適用, 如:老年代, s0/s1一個(gè)時(shí)刻只能使用其中一塊, 內(nèi)存使用率低分代算法: 年輕代采用復(fù)制清除, 老年代使用標(biāo)記清除/壓縮
垃圾收集器及內(nèi)存分配
- 串行垃圾收集器: GC過程, 只有一個(gè)線程工作, 且應(yīng)用要停止運(yùn)行(Stop-the-world), 等待GC完成.
設(shè)置VM Optional: 使用串行GC器, 打印GC細(xì)節(jié)
運(yùn)行結(jié)果如下:
日志解讀(使用第一行數(shù)據(jù)):
- 并行垃圾回收器: 在串行GC的基礎(chǔ)上, 變?yōu)槎嗑€程進(jìn)行GC操作(存在Stop-the-world), 其余與串行GC一樣
- ParNew垃圾收集器
只能在年輕代工作(只是將串行GC變?yōu)椴⑿蠫C), 使用-XX:+UseParNewGC設(shè)置, 老年代依舊采用串行GC
測(cè)試代碼在上一個(gè)代碼的基礎(chǔ)上修改VM options
運(yùn)行過程中, 發(fā)現(xiàn)相比于SerialGC, ParNew在GC上存在一定的提升 - ParallelGC垃圾收集器
與ParNew一樣, 新增多個(gè)與吞吐量相關(guān)的參數(shù), 操作更加靈活
- ParNew垃圾收集器
測(cè)試代碼與前一個(gè)一樣, 只修改VM options, 運(yùn)行結(jié)果如下:
- CMS垃圾處理器
CMS(Concurrent Mark Sweep): 針對(duì)老年代(對(duì)老年代GC進(jìn)行改進(jìn)), 使用標(biāo)記清除算法, -XX:UseConcurrentMarkSweepGC設(shè)置.
執(zhí)行過程如下:
程序打印的日志也是按照上面的流程, 程序運(yùn)行結(jié)果如下:
G1垃圾收集器(jdk1.7使用)
G1取消傳統(tǒng)的新生代, 老年代物理劃分, 將內(nèi)存空間變?yōu)槿舾蓚€(gè)區(qū)域, 每個(gè)區(qū)域包含邏輯上的新生代, 老年代. G1存在YoungGC, MixedGC, FullGC, 在不同的條件下觸發(fā)
優(yōu): 每一塊區(qū)域存在多種狀態(tài)(Old, Eden, Humongous, Survivor)解決碎片化問題, 即使在正常處理過程中, 都能解決內(nèi)存壓縮問題G1的YoungGC
Eden區(qū)空間耗盡觸發(fā), EdenGC, Eden中數(shù)據(jù)移動(dòng)到Survivor區(qū)(Survivor滿了, 數(shù)據(jù)移動(dòng)到新的Survivor區(qū), 部分?jǐn)?shù)據(jù)移動(dòng)到Old區(qū)), 部分?jǐn)?shù)據(jù)移動(dòng)到Old區(qū), 當(dāng)前Eden清空, 變?yōu)槲词褂脜^(qū)
RememberSet(記憶集合)
RememberSet解決新生代尋找根對(duì)象的問題, 每一個(gè)區(qū)域初始化都生成一個(gè)RememberSet, 該集合保存其他對(duì)象引用"我"的記錄, 掃描RememberSet就能得出對(duì)象之間的引用關(guān)系, 而不再需要對(duì)新生代, 老年代中所有對(duì)象進(jìn)行掃描.
G1的MixedGC
為避免堆內(nèi)存被耗盡, JVM啟動(dòng)MixedGC, 回收所有的Young區(qū), 回收部分Old區(qū)(MixedGC不是FullGC).
使用-XX:InitiatingHeapOccupancyPercent=n(老年代占整個(gè)堆大小百分比閾值) 決定MixedGC什么時(shí)候觸發(fā)
MixedGC分為2個(gè)步驟: 全局并發(fā)標(biāo)記(前5個(gè)步驟), 拷貝存活對(duì)象(第6個(gè)步驟)
G1相關(guān)參數(shù)
-XX:+UseG1GC 使用 G1 垃圾收集器 -XX:MaxGCPauseMillis 設(shè)置期望達(dá)到的最大GC停頓時(shí)間指標(biāo)(JVM會(huì)盡力實(shí)現(xiàn),但不保證達(dá)到),默認(rèn) 值是 200 毫秒。 -XX:G1HeapRegionSize=n 設(shè)置的 G1 區(qū)域的大小。值是 2 的冪,范圍是 1 MB 到 32 MB 之間。目標(biāo)是根 據(jù)最小的 Java 堆大小劃分出約 2048 個(gè)區(qū)域。 默認(rèn)是堆內(nèi)存的1/2000。 -XX:ParallelGCThreads=n 設(shè)置 STW 工作線程數(shù)的值。將 n 的值設(shè)置為邏輯處理器的數(shù)量。n 的值與邏輯 處理器的數(shù)量相同,最多為 8。 -XX:ConcGCThreads=n 設(shè)置并行標(biāo)記的線程數(shù)。將 n 設(shè)置為并行垃圾回收線程數(shù) (ParallelGCThreads) 的 1/4 左右。 -XX:InitiatingHeapOccupancyPercent=n 設(shè)置觸發(fā)標(biāo)記周期的 Java 堆占用率閾值。默認(rèn)占用率是整個(gè) Java 堆的 45%。G1日志輸出參數(shù)
‐XX:+PrintGC 輸出GC日志 ‐XX:+PrintGCDetails 輸出GC的詳細(xì)日志 ‐XX:+PrintGCTimeStamps 輸出GC的時(shí)間戳(以基準(zhǔn)時(shí)間的形式) ‐XX:+PrintGCDateStamps 輸出GC的時(shí)間戳(以日期的形式,如 2013‐05‐ 04T21:53:59.234+0800) ‐XX:+PrintHeapAtGC 在進(jìn)行GC的前后打印出堆的信息 ‐Xloggc:../logs/gc.log 日志文件的輸出路徑測(cè)試
代碼運(yùn)行完畢自動(dòng)將GC日志輸入到項(xiàng)目下的gc.log中
使用GC Easy進(jìn)行分析(http://gceasy.io)
將gc.log上傳該網(wǎng)站, 就能進(jìn)行GC分析, 獲取分析報(bào)告
總結(jié)
以上是生活随笔為你收集整理的Java常见GC算法_垃圾收集器及内存分配_G1垃圾收集器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python爬酷狗音乐_良心推荐!一个P
- 下一篇: java美元兑换,(Java实现) 美元