先來(lái)看看5種JVM垃圾收集器特點(diǎn)
10年積累的網(wǎng)站制作、做網(wǎng)站經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問(wèn)題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站策劃后付款的網(wǎng)站建設(shè)流程,更有剛察免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
現(xiàn)在常見(jiàn)的垃圾收集器有如下幾種:
新生代收集器:
Serial
ParNew
Parallel Scavenge
老年代收集器:
Serial Old
CMS
Parallel Old
堆內(nèi)存垃圾收集器:G1
每種垃圾收集器之間有連線,表示他們可以搭配使用。
(1)Serial 收集器
Serial 是一款用于新生代的單線程收集器,采用復(fù)制算法進(jìn)行垃圾收集。Serial 進(jìn)行垃圾收集時(shí),不僅只用一條線程執(zhí)行垃圾收集工作,它在收集的同時(shí),所有的用戶線程必須暫停(Stop The World)。
就比如媽媽在家打掃衛(wèi)生的時(shí)候,肯定不會(huì)邊打掃邊讓兒子往地上亂扔紙屑,否則一邊制造垃圾,一遍清理垃圾,這活啥時(shí)候也干不完。
如下是 Serial 收集器和 Serial Old 收集器結(jié)合進(jìn)行垃圾收集的示意圖,當(dāng)用戶線程都執(zhí)行到安全點(diǎn)時(shí),所有線程暫停執(zhí)行,Serial 收集器以單線程,采用復(fù)制算法進(jìn)行垃圾收集工作,收集完之后,用戶線程繼續(xù)開(kāi)始執(zhí)行。
適用場(chǎng)景:Client 模式(桌面應(yīng)用);單核服務(wù)器。
可以用 -XX:+UserSerialGC 來(lái)選擇 Serial 作為新生代收集器。
(2)ParNew 收集器
ParNew 就是一個(gè) Serial 的多線程版本,其它與Serial并無(wú)區(qū)別。ParNew 在單核 CPU 環(huán)境并不會(huì)比 Serial 收集器達(dá)到更好的效果,它默認(rèn)開(kāi)啟的收集線程數(shù)和 CPU 數(shù)量一致,可以通過(guò) -XX:ParallelGCThreads 來(lái)設(shè)置垃圾收集的線程數(shù)。
如下是 ParNew 收集器和 Serial Old 收集器結(jié)合進(jìn)行垃圾收集的示意圖,當(dāng)用戶線程都執(zhí)行到安全點(diǎn)時(shí),所有線程暫停執(zhí)行,ParNew 收集器以多線程,采用復(fù)制算法進(jìn)行垃圾收集工作,收集完之后,用戶線程繼續(xù)開(kāi)始執(zhí)行。
適用場(chǎng)景:多核服務(wù)器;與 CMS 收集器搭配使用。當(dāng)使用 -XX:+UserConcMarkSweepGC 來(lái)選擇 CMS 作為老年代收集器時(shí),新生代收集器默認(rèn)就是 ParNew,也可以用 -XX:+UseParNewGC 來(lái)指定使用 ParNew 作為新生代收集器。
(3)Parallel Scavenge 收集器
Parallel Scavenge 也是一款用于新生代的多線程收集器,與 ParNew 的不同之處是ParNew 的目標(biāo)是盡可能縮短垃圾收集時(shí)用戶線程的停頓時(shí)間,Parallel Scavenge 的目標(biāo)是達(dá)到一個(gè)可控制的吞吐量。
吞吐量就是 CPU 執(zhí)行用戶線程的的時(shí)間與 CPU 執(zhí)行總時(shí)間的比值【吞吐量 = 運(yùn)行用戶代代碼時(shí)間/(運(yùn)行用戶代碼時(shí)間+垃圾收集時(shí)間)】,比如虛擬機(jī)一共運(yùn)行了 100 分鐘,其中垃圾收集花費(fèi)了 1 分鐘,那吞吐量就是 99% 。比如下面兩個(gè)場(chǎng)景,垃圾收集器每 100 秒收集一次,每次停頓 10 秒,和垃圾收集器每 50 秒收集一次,每次停頓時(shí)間 7 秒,雖然后者每次停頓時(shí)間變短了,但是總體吞吐量變低了,CPU 總體利用率變低了。
可以通過(guò) -XX:MaxGCPauseMillis 來(lái)設(shè)置收集器盡可能在多長(zhǎng)時(shí)間內(nèi)完成內(nèi)存回收,可以通過(guò) -XX:GCTimeRatio 來(lái)精確控制吞吐量。
如下是 Parallel 收集器和 Parallel Old 收集器結(jié)合進(jìn)行垃圾收集的示意圖,在新生代,當(dāng)用戶線程都執(zhí)行到安全點(diǎn)時(shí),所有線程暫停執(zhí)行,ParNew 收集器以多線程,采用復(fù)制算法進(jìn)行垃圾收集工作,收集完之后,用戶線程繼續(xù)開(kāi)始執(zhí)行;在老年代,當(dāng)用戶線程都執(zhí)行到安全點(diǎn)時(shí),所有線程暫停執(zhí)行,Parallel Old 收集器以多線程,采用標(biāo)記整理算法進(jìn)行垃圾收集工作。
適用場(chǎng)景:注重吞吐量,高效利用 CPU,需要高效運(yùn)算且不需要太多交互。
可以使用 -XX:+UseParallelGC 來(lái)選擇 Parallel Scavenge 作為新生代收集器,jdk7、jdk8 默認(rèn)使用 Parallel Scavenge 作為新生代收集器。
(1)Serial Old 收集器
Serial Old 收集器是 Serial 的老年代版本,同樣是一個(gè)單線程收集器,采用標(biāo)記-整理算法。
如下圖是 Serial 收集器和 Serial Old 收集器結(jié)合進(jìn)行垃圾收集的示意圖:
適用場(chǎng)景:Client 模式(桌面應(yīng)用);單核服務(wù)器;與 Parallel Scavenge 收集器搭配;作為 CMS 收集器的后備預(yù)案。
(2)CMS(Concurrent Mark Sweep) 收集器
CMS 收集器是一種以最短回收停頓時(shí)間為目標(biāo)的收集器,以 “ 最短用戶線程停頓時(shí)間 ” 著稱。整個(gè)垃圾收集過(guò)程分為 4 個(gè)步驟:
① 初始標(biāo)記:標(biāo)記一下 GC Roots 能直接關(guān)聯(lián)到的對(duì)象,速度較快。
② 并發(fā)標(biāo)記:進(jìn)行 GC Roots Tracing,標(biāo)記出全部的垃圾對(duì)象,耗時(shí)較長(zhǎng)。
③ 重新標(biāo)記:修正并發(fā)標(biāo)記階段引用戶程序繼續(xù)運(yùn)行而導(dǎo)致變化的對(duì)象的標(biāo)記記錄,耗時(shí)較短。
④ 并發(fā)清除:用標(biāo)記-清除算法清除垃圾對(duì)象,耗時(shí)較長(zhǎng)。
整個(gè)過(guò)程耗時(shí)最長(zhǎng)的并發(fā)標(biāo)記和并發(fā)清除都是和用戶線程一起工作,所以從總體上來(lái)說(shuō),CMS 收集器垃圾收集可以看做是和用戶線程并發(fā)執(zhí)行的。
CMS 收集器也存在一些缺點(diǎn):
對(duì) CPU 資源敏感:默認(rèn)分配的垃圾收集線程數(shù)為(CPU 數(shù)+3)/4,隨著 CPU 數(shù)量下降,占用 CPU 資源越多,吞吐量越小
無(wú)法處理浮動(dòng)垃圾:在并發(fā)清理階段,由于用戶線程還在運(yùn)行,還會(huì)不斷產(chǎn)生新的垃圾,CMS 收集器無(wú)法在當(dāng)次收集中清除這部分垃圾。同時(shí)由于在垃圾收集階段用戶線程也在并發(fā)執(zhí)行,CMS 收集器不能像其他收集器那樣等老年代被填滿時(shí)再進(jìn)行收集,需要預(yù)留一部分空間提供用戶線程運(yùn)行使用。當(dāng) CMS 運(yùn)行時(shí),預(yù)留的內(nèi)存空間無(wú)法滿足用戶線程的需要,就會(huì)出現(xiàn) “ Concurrent Mode Failure ”的錯(cuò)誤,這時(shí)將會(huì)啟動(dòng)后備預(yù)案,臨時(shí)用 Serial Old 來(lái)重新進(jìn)行老年代的垃圾收集。
因?yàn)?CMS 是基于標(biāo)記-清除算法,所以垃圾回收后會(huì)產(chǎn)生空間碎片,可以通過(guò) -XX:UserCMSCompactAtFullCollection 開(kāi)啟碎片整理(默認(rèn)開(kāi)啟),在 CMS 進(jìn)行 Full GC 之前,會(huì)進(jìn)行內(nèi)存碎片的整理。還可以用 -XX:CMSFullGCsBeforeCompaction 設(shè)置執(zhí)行多少次不壓縮(不進(jìn)行碎片整理)的 Full GC 之后,跟著來(lái)一次帶壓縮(碎片整理)的 Full GC。
適用場(chǎng)景:重視服務(wù)器響應(yīng)速度,要求系統(tǒng)停頓時(shí)間最短。可以使用 -XX:+UserConMarkSweepGC 來(lái)選擇 CMS 作為老年代收集器。
(3)Parallel Old 收集器
Parallel Old 收集器是 Parallel Scavenge 的老年代版本,是一個(gè)多線程收集器,采用標(biāo)記-整理算法。可以與 Parallel Scavenge 收集器搭配,可以充分利用多核 CPU 的計(jì)算能力。
適用場(chǎng)景:與Parallel Scavenge 收集器搭配使用;注重吞吐量。jdk7、jdk8 默認(rèn)使用該收集器作為老年代收集器,使用 -XX:+UseParallelOldGC 來(lái)指定使用 Paralle Old 收集器。
G1 收集器
G1 收集器是 jdk1.7 才正式引用的商用收集器,現(xiàn)在已經(jīng)成為 jdk9 默認(rèn)的收集器。前面幾款收集器收集的范圍都是新生代或者老年代,G1 進(jìn)行垃圾收集的范圍是整個(gè)堆內(nèi)存,它采用 “ 化整為零 ” 的思路,把整個(gè)堆內(nèi)存劃分為多個(gè)大小相等的獨(dú)立區(qū)域(Region),在 G1 收集器中還保留著新生代和老年代的概念,它們分別都是一部分 Region,如下圖:
每一個(gè)方塊就是一個(gè)區(qū)域,每個(gè)區(qū)域可能是 Eden、Survivor、老年代,每種區(qū)域的數(shù)量也不一定。JVM 啟動(dòng)時(shí)會(huì)自動(dòng)設(shè)置每個(gè)區(qū)域的大小(1M ~ 32M,必須是 2 的次冪),最多可以設(shè)置 2048 個(gè)區(qū)域(即支持的最大堆內(nèi)存為 32M*2048 = 64G),假如設(shè)置 -Xmx8g -Xms8g,則每個(gè)區(qū)域大小為 8g/2048=4M。
為了在 GC Roots Tracing 的時(shí)候避免掃描全堆,在每個(gè) Region 中,都有一個(gè) Remembered Set 來(lái)實(shí)時(shí)記錄該區(qū)域內(nèi)的引用類型數(shù)據(jù)與其他區(qū)域數(shù)據(jù)的引用關(guān)系(在前面的幾款分代收集中,新生代、老年代中也有一個(gè) Remembered Set 來(lái)實(shí)時(shí)記錄與其他區(qū)域的引用關(guān)系),在標(biāo)記時(shí)直接參考這些引用關(guān)系就可以知道這些對(duì)象是否應(yīng)該被清除,而不用掃描全堆的數(shù)據(jù)。
G1 收集器可以 “ 建立可預(yù)測(cè)的停頓時(shí)間模型 ”,它維護(hù)了一個(gè)列表用于記錄每個(gè) Region 回收的價(jià)值大小(回收后獲得的空間大小以及回收所需時(shí)間的經(jīng)驗(yàn)值),這樣可以保證 G1 收集器在有限的時(shí)間內(nèi)可以獲得最大的回收效率。
如下圖所示,G1 收集器收集器收集過(guò)程有初始標(biāo)記、并發(fā)標(biāo)記、最終標(biāo)記、篩選回收,和 CMS 收集器前幾步的收集過(guò)程很相似:
① 初始標(biāo)記:標(biāo)記出 GC Roots 直接關(guān)聯(lián)的對(duì)象,這個(gè)階段速度較快,需要停止用戶線程,單線程執(zhí)行。
② 并發(fā)標(biāo)記:從 GC Root 開(kāi)始對(duì)堆中的對(duì)象進(jìn)行可達(dá)新分析,找出存活對(duì)象,這個(gè)階段耗時(shí)較長(zhǎng),但可以和用戶線程并發(fā)執(zhí)行。
③ 最終標(biāo)記:修正在并發(fā)標(biāo)記階段引用戶程序執(zhí)行而產(chǎn)生變動(dòng)的標(biāo)記記錄。
④ 篩選回收:篩選回收階段會(huì)對(duì)各個(gè) Region 的回收價(jià)值和成本進(jìn)行排序,根據(jù)用戶所期望的 GC 停頓時(shí)間來(lái)指定回收計(jì)劃(用最少的時(shí)間來(lái)回收包含垃圾最多的區(qū)域,這就是 Garbage First 的由來(lái)——第一時(shí)間清理垃圾最多的區(qū)塊),這里為了提高回收效率,并沒(méi)有采用和用戶線程并發(fā)執(zhí)行的方式,而是停頓用戶線程。
適用場(chǎng)景:要求盡可能可控 GC 停頓時(shí)間;內(nèi)存占用較大的應(yīng)用。可以用 -XX:+UseG1GC 使用 G1 收集器,jdk9 默認(rèn)使用 G1 收集器。
本文主要介紹了JVM中的垃圾回收器,主要包括串行回收器、并行回收器以及CMS回收器、G1回收器。他們各自都有優(yōu)缺點(diǎn),通常來(lái)說(shuō)你需要根據(jù)你的業(yè)務(wù),進(jìn)行基于垃圾回收器的性能測(cè)試,然后再做選擇。下面給出配置回收器時(shí),經(jīng)常使用的參數(shù):
-XX:+UseSerialGC:在新生代和老年代使用串行收集器
-XX:+UseParNewGC:在新生代使用并行收集器
-XX:+UseParallelGC :新生代使用并行回收收集器,更加關(guān)注吞吐量
-XX:+UseParallelOldGC:老年代使用并行回收收集器
-XX:ParallelGCThreads:設(shè)置用于垃圾回收的線程數(shù)
-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:設(shè)定CMS的線程數(shù)量
-XX:+UseG1GC:?jiǎn)⒂肎1垃圾回收器
接下來(lái)看看8種JVM內(nèi)存溢出原因
發(fā)生頻率:5顆星
造成原因
無(wú)法在 Java 堆中分配對(duì)象
吞吐量增加
應(yīng)用程序無(wú)意中保存了對(duì)象引用,對(duì)象無(wú)法被 GC 回收
應(yīng)用程序過(guò)度使用 finalizer。finalizer 對(duì)象不能被 GC 立刻回收。finalizer 由結(jié)束隊(duì)列服務(wù)的守護(hù)線程調(diào)用,有時(shí) finalizer 線程的處理能力無(wú)法跟上結(jié)束隊(duì)列的增長(zhǎng)
解決方案
使用 -Xmx 增加堆大小
修復(fù)應(yīng)用程序中的內(nèi)存泄漏
發(fā)生頻率:5顆星
造成原因
Java 進(jìn)程98%的時(shí)間在進(jìn)行垃圾回收,恢復(fù)了不到2%的堆空間,最后連續(xù)5個(gè)(編譯時(shí)常量)垃圾回收一直如此。
解決方案
使用 -Xmx 增加堆大小
使用 -XX:-UseGCOverheadLimit 取消 GC 開(kāi)銷限制
修復(fù)應(yīng)用程序中的內(nèi)存泄漏
發(fā)生頻率:2顆星
造成原因
應(yīng)用程序試圖分配一個(gè)超過(guò)堆大小的數(shù)組
解決方案
使用 -Xmx 增加堆大小
修復(fù)應(yīng)用程序中分配巨大數(shù)組的 bug
發(fā)生頻率:3顆星
造成原因
Perm gen 空間包含:
類的名字、字段、方法
與類相關(guān)的對(duì)象數(shù)組和類型數(shù)組
JIT 編譯器優(yōu)化
當(dāng) Perm gen 空間用盡時(shí),將拋出異常。
解決方案
使用 -XX: MaxPermSize 增加 Permgen 大小
不重啟應(yīng)用部署應(yīng)用程序可能會(huì)導(dǎo)致此問(wèn)題。重啟 JVM 解決
發(fā)生頻率:3顆星
造成原因
從 Java 8 開(kāi)始 Perm gen 改成了 Metaspace,在本機(jī)內(nèi)存中分配 class 元數(shù)據(jù)(稱為 metaspace)。如果 metaspace 耗盡,則拋出異常
解決方案
通過(guò)命令行設(shè)置 -XX: MaxMetaSpaceSize 增加 metaspace 大小
取消 -XX: maxmetsspacedize
減小 Java 堆大小,為 MetaSpace 提供更多的可用空間
為服務(wù)器分配更多的內(nèi)存
可能是應(yīng)用程序 bug,修復(fù) bug
發(fā)生頻率:5顆星
造成原因
內(nèi)存不足,無(wú)法創(chuàng)建新線程。由于線程在本機(jī)內(nèi)存中創(chuàng)建,報(bào)告這個(gè)錯(cuò)誤表明本機(jī)內(nèi)存空間不足
解決方案
為機(jī)器分配更多的內(nèi)存
減少 Java 堆空間
修復(fù)應(yīng)用程序中的線程泄漏。
增加操作系統(tǒng)級(jí)別的限制
ulimit -a
用戶進(jìn)程數(shù)增大 (-u) 1800
使用 -Xss 減小線程堆棧大小
發(fā)生頻率:1顆星
造成原因
內(nèi)核任務(wù):內(nèi)存不足結(jié)束器,在可用內(nèi)存極低的情況下會(huì)殺死進(jìn)程
解決方案
將進(jìn)程遷移到不同的機(jī)器上
給機(jī)器增加更多內(nèi)存
與其他 OOM 錯(cuò)誤不同,這是由操作系統(tǒng)而非 JVM 觸發(fā)的。
發(fā)生頻率:1顆星
造成原因
本機(jī)方法(native method)分配失敗
打印的堆棧跟蹤信息,最頂層的幀是本機(jī)方法
解決方案
使用操作系統(tǒng)本地工具進(jìn)行診斷
最后
歡迎大家一起交流,喜歡文章記得點(diǎn)個(gè)贊喲,感謝支持!
網(wǎng)站題目:5種JVM垃圾收集器特點(diǎn)和8種JVM內(nèi)存溢出原因
鏈接地址:http://vcdvsql.cn/article34/iijose.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、虛擬主機(jī)、網(wǎng)站改版、域名注冊(cè)、關(guān)鍵詞優(yōu)化、網(wǎng)站導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)