您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“JVM有哪些常用的功能”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
Hello,今天給各位童鞋們分享JVM,趕緊拿出小本子記下來(lái)吧!
新生代GC場(chǎng)景
在jvm內(nèi)存模型中,新生代的內(nèi)存分為為Eden和兩個(gè)Survivor
在系統(tǒng)不停的運(yùn)行過(guò)程中,Eden區(qū)會(huì)被塞滿,這個(gè)時(shí)候就會(huì)觸發(fā)Minor GC,進(jìn)行垃圾回收有專門的垃圾回收線程,不同的內(nèi)存區(qū)域會(huì)有不同的垃圾回收器,相當(dāng)于垃圾回收線程和垃圾回收器配合起來(lái),使用自己的垃圾回收算法,對(duì)指定的內(nèi)存區(qū)域進(jìn)行垃圾回收,如下圖所示:
針對(duì)新生代采用ParNew垃圾回收器來(lái)進(jìn)行回收,然后ParNew垃圾回收器針對(duì)新生代采用的就是復(fù)制算法來(lái)垃圾回收
這個(gè)時(shí)候垃圾回收器,就會(huì)把Eden區(qū)中的存活對(duì)象都標(biāo)記出來(lái),然后全部轉(zhuǎn)移到Survivor1去,接著一次性清空掉Eden中的垃圾對(duì)象
當(dāng)Eden再次塞滿的時(shí)候,就又要觸發(fā)Minor GC了,此時(shí)已然是垃圾回收線程運(yùn)行垃圾回收器中的算法邏輯,也就是采用復(fù)制算法邏輯,去標(biāo)記出來(lái)Eden和Survivor1中的存活對(duì)象,然后一次性把存活對(duì)象轉(zhuǎn)移到Survivor2中去,接著把Eden和Survivor1中的垃圾對(duì)象都回收掉
在發(fā)生GC的時(shí)候,我們寫好的JAVA系統(tǒng)在運(yùn)行期間還能不能繼續(xù)在新生代里創(chuàng)建新的對(duì)象?
假如在GC期間,允許創(chuàng)建新的對(duì)象,那么垃圾回收器在把Eden和Survivor1里的存活對(duì)象標(biāo)記轉(zhuǎn)移到Survivor2去,然后還在想辦法把Eden和Survivor1里的垃圾對(duì)象都清理掉,結(jié)果這個(gè)時(shí)候系統(tǒng)程序還在不停的在Eden里創(chuàng)建新的對(duì)象,那么這些新對(duì)象很快就成了垃圾對(duì)象,有的還有人引用是存活對(duì)象,這對(duì)垃圾回收器完全亂套,一邊回收一邊還在創(chuàng)建新的對(duì)象。
Stop the World
JVM最大的痛點(diǎn),就是垃圾回收的過(guò)程,在垃圾回收的時(shí)候,盡可能讓垃圾回收器專心的工作,不能隨便讓我們的Java應(yīng)用繼續(xù)創(chuàng)建對(duì)象,所以此時(shí)JVM會(huì)在后臺(tái)進(jìn)入“入“Stop the World”狀態(tài),也就是說(shuō)會(huì)直接停止我們的Java系統(tǒng)的所有工作線程,讓我們的代碼不再運(yùn)行
這樣的話,就可以讓我們的系統(tǒng)暫停運(yùn)行,然后不再創(chuàng)建新的對(duì)象,同時(shí)讓垃圾回收線程盡快完成垃圾回收的工作,就是標(biāo)記和轉(zhuǎn)移Eden以及Survivor1的存活對(duì)象到Survivor2中去,然后盡快一次性回收掉Eden和Survivor1中的垃圾對(duì)象,等垃圾回收完畢后,繼續(xù)恢復(fù)我們寫的Java系統(tǒng)的工作線程,然后繼續(xù)運(yùn)行我們的代碼邏輯,繼續(xù)在Eden區(qū)創(chuàng)建新的對(duì)象
Stop the World造成的系統(tǒng)停頓
在運(yùn)行GC的時(shí)候會(huì)無(wú)法創(chuàng)建新的對(duì)象,則會(huì)造車系統(tǒng)停頓,如果Minor GC要運(yùn)行50ms,則可能會(huì)導(dǎo)致我們的系統(tǒng)在50ms內(nèi)不能接受任何請(qǐng)求,在這50ms期間用戶發(fā)起的所有請(qǐng)求都會(huì)出現(xiàn)短暫的卡頓,因?yàn)橄到y(tǒng)的工作線程不在運(yùn)行,不能處理請(qǐng)求
可能由于內(nèi)存分配不合理,導(dǎo)致對(duì)象頻繁進(jìn)入老年代,平均七八分鐘一次Full GC,而Full GC比較慢,一次回收可能需要幾秒甚至幾十秒,所以一旦頻繁的Full GC,就會(huì)造成系統(tǒng)每隔幾分鐘卡死個(gè)幾十秒,讓用戶體驗(yàn)極差
所以說(shuō),無(wú)論是新生代GC還是老年代GC,都盡量不要讓頻率過(guò)高,也避免持續(xù)時(shí)間過(guò)長(zhǎng),避免影響系統(tǒng)正常運(yùn)行,這也是使用JVM過(guò)程中一個(gè)最需要優(yōu)化的地方,也是最大的一個(gè)痛點(diǎn)。
不同的垃圾回收器的不同的影響
Serial垃圾回收器(新生代)
用一個(gè)線程進(jìn)行垃圾回收,然后此時(shí)暫停系統(tǒng)工作線程
一般我們?cè)?a title="服務(wù)器" target="_blank" href="http://kemok4.com/">服務(wù)器程序中很少用這種方式
ParNew垃圾回收器(新生代)
常用的新生代垃圾回收器
針對(duì)服務(wù)器一般都是多核CPU做了優(yōu)化,他是支持多線程個(gè)垃圾回收的,可以大幅度提升回收的性能,縮短回收的時(shí)間
Serial和Serial Old垃圾回收器
分別用來(lái)回收新生代和老年代的垃圾對(duì)象
工作原理就是單線程運(yùn)行,垃圾回收的時(shí)候會(huì)停止我們自己寫的系統(tǒng)的其他工作線程,讓我們系統(tǒng)直接卡死不動(dòng),然后讓他們垃圾回收,這個(gè)現(xiàn)在一般寫后臺(tái)Java系統(tǒng)幾乎不用。
ParNew和CMS垃圾回收器
ParNew現(xiàn)在一般都是用在新生代的垃圾回收器,采用的就是復(fù)制算法來(lái)垃圾回收
CMS是用在老年代的垃圾回收器
都是多線程并發(fā)的機(jī)制,性能更好,現(xiàn)在一般是線上生產(chǎn)系統(tǒng)的標(biāo)配組合
ParNew
理論
沒有最新的G1垃圾回收器的話,通常大家線上系統(tǒng)都是ParNew垃圾回收器作為新生代的垃圾回收器當(dāng)然現(xiàn)在即使有了G1,其實(shí)很多線上系統(tǒng)還是用的ParNew
通常運(yùn)行在服務(wù)器上Java系統(tǒng),都可以充分利用服務(wù)器的多核CPU優(yōu)勢(shì),如果對(duì)新生代回收的時(shí)候,僅僅使用單線程進(jìn)行垃圾回收,會(huì)導(dǎo)致浪費(fèi)CPU的資源
新生代的ParNew垃圾回收器主打的就是多線程垃圾回收機(jī)制,另外一種Serial垃圾回收器主打的是單線程垃圾回收,他們倆都是回收新生代的,唯一的區(qū)別就是單線程和多線程的區(qū)別,但是垃圾回收算法是完全一樣
ParNew垃圾回收器如果一旦在合適的時(shí)機(jī)執(zhí)行Minor GC的時(shí)候,就會(huì)把系統(tǒng)程序的工作線程全部停掉,禁止程序繼續(xù)運(yùn)行創(chuàng)建新的對(duì)象,然后自己就用多個(gè)垃圾回收線程去進(jìn)行垃圾回收,回收的機(jī)制和算法都是一樣的
參數(shù)設(shè)置
部署到Tomcat時(shí)可以在Tomcat的catalina.sh中設(shè)置Tomcat的JVM參數(shù),使用Spring Boot也可以在啟動(dòng)時(shí)指定JVM參數(shù)。
指定使用ParNew垃圾回收器
使用“-XX:+UseParNewGC”選項(xiàng),只要加入這個(gè)選項(xiàng),JVM啟動(dòng)之后對(duì)新生代進(jìn)行垃圾回收的,就是ParNew垃圾回收器
ParNew垃圾回收器默認(rèn)情況下的線程數(shù)量
一旦我們指定了使用ParNew垃圾回收器之后,他默認(rèn)給自己設(shè)置的垃圾回收線程的數(shù)量就是跟CPU的核數(shù)是一樣的
如果你一定要自己調(diào)節(jié)ParNew的垃圾回收線程數(shù)量,也是可以的,使用“-XX:ParallelGCThreads”參數(shù)即可,通過(guò)他可以設(shè)置線程的數(shù)量
CMS
理論
老年代選擇的垃圾回收器是CMS,他采用的是標(biāo)記清理算法
標(biāo)記清理算法:先通過(guò)GC Roots的方法,看各個(gè)對(duì)象是否被GC Roots給引用,如果是的話,那就是存活對(duì)象,否則就是垃圾對(duì)象。先將垃圾對(duì)象都標(biāo)記出來(lái),然后一次性把垃圾對(duì)象都回收掉,這種方法最大問題:就是會(huì)造成很多內(nèi)存碎片,這種內(nèi)存碎片不大不小,可能放不下任何一個(gè)對(duì)象,則會(huì)造成內(nèi)存浪費(fèi)
CMS的STW(Stop the World)問題:如果停止一切工作線程,然后慢慢的執(zhí)行“標(biāo)記-清理”算法,會(huì)導(dǎo)致系統(tǒng)卡死時(shí)間過(guò)長(zhǎng),很多響應(yīng)無(wú)法處理。所以CMS垃圾回收器采取的是:垃圾回收線程和系統(tǒng)工作線程盡量同時(shí)執(zhí)行的模式來(lái)處理
如何實(shí)現(xiàn)系統(tǒng)一邊工作的同時(shí)進(jìn)行垃圾回收?
CMS在執(zhí)行一次垃圾回收的過(guò)程共分為4個(gè)階段:
初始標(biāo)記
并發(fā)標(biāo)記
重新標(biāo)記
并發(fā)清理
1、初始標(biāo)記
CMS在進(jìn)行垃圾回收時(shí),會(huì)先執(zhí)行初始標(biāo)記階段。這個(gè)階段會(huì)讓系統(tǒng)的工作線程全部停止,進(jìn)入“Stop The World”狀態(tài),初始標(biāo)記執(zhí)行STW影響不大,因?yàn)樗乃俣缺容^快,只是標(biāo)記出GC Roots直接應(yīng)用的對(duì)象
2、并發(fā)標(biāo)記
這個(gè)階段會(huì)讓系統(tǒng)可以隨意創(chuàng)建各種新對(duì)象,繼續(xù)運(yùn)行,在運(yùn)行期間可能會(huì)創(chuàng)建新的存活對(duì)象,也可能會(huì)讓部分存活對(duì)象失去引用,變成垃圾對(duì)象。在這個(gè)過(guò)程中,垃圾回收線程,會(huì)盡可能的對(duì)已有的對(duì)象進(jìn)行GC Roots追蹤,但是這個(gè)過(guò)程中,在進(jìn)行并發(fā)標(biāo)記的時(shí)候,系統(tǒng)程序會(huì)不停的工作,他可能會(huì)各種創(chuàng)建出來(lái)新的對(duì)象,部分對(duì)象可能成為垃圾
這個(gè)階段就是對(duì)老年代所有對(duì)象進(jìn)行GC Roots追蹤,其實(shí)是最耗時(shí)的,需要追蹤所有對(duì)象是否從根源上被GC Roots引用了,但是這個(gè)最耗時(shí)的階段,是跟系統(tǒng)程序并發(fā)運(yùn)行的,所以其實(shí)這個(gè)階段不會(huì)對(duì)系統(tǒng)運(yùn)行造成影響。
3、重新標(biāo)記
因?yàn)榈诙A段里,你一邊標(biāo)記存活對(duì)象和垃圾對(duì)象,一邊系統(tǒng)在不停運(yùn)行創(chuàng)建新對(duì)象,讓老對(duì)象變成垃圾,所以第二階段結(jié)束之后,絕對(duì)會(huì)有很多存活對(duì)象和垃圾對(duì)象,是之前第二階段沒標(biāo)記出來(lái)的。所以此時(shí)進(jìn)入第三階段,要繼續(xù)讓系統(tǒng)程序停下來(lái),**再次進(jìn)入“Stop the World”階段。**然后重新標(biāo)記下在第二階段里新創(chuàng)建的一些對(duì)象,還有一些已有對(duì)象可能失去引用變成垃圾的情況
這個(gè)重新標(biāo)記的階段,是速度很快的,他其實(shí)就是對(duì)在第二階段中被系統(tǒng)程序運(yùn)行變動(dòng)過(guò)的少數(shù)對(duì)象進(jìn)行標(biāo)記,所以運(yùn)行速度很快,接著重新恢復(fù)系統(tǒng)程序的運(yùn)行。
4、并發(fā)清理
讓系統(tǒng)程序隨意運(yùn)行,然后他來(lái)清理掉之前標(biāo)記為垃圾的對(duì)象,這個(gè)階段比較耗時(shí),需要進(jìn)行對(duì)象的清理,但是他是跟著系統(tǒng)程序并發(fā)運(yùn)行的,所以也不影響系統(tǒng)程序的執(zhí)行
CMS垃圾回收器問題
1、并發(fā)回收導(dǎo)致CPU資源緊張
CMS垃圾回收器有一個(gè)最大的問題,雖然能在垃圾回收的同時(shí)讓系統(tǒng)同時(shí)工作,在并發(fā)標(biāo)記和并發(fā)清理兩個(gè)最耗時(shí)的階段,垃圾回收線程和系統(tǒng)工作線程同時(shí)工作,會(huì)導(dǎo)致有限的CPU資源被垃圾回收線程占用了一部分
并發(fā)標(biāo)記的時(shí)候,需要對(duì)GC Roots進(jìn)行深度追蹤,看所有對(duì)象里面到底有多少人是存活的但是因?yàn)槔夏甏锎婊顚?duì)象是比較多的,這個(gè)過(guò)程會(huì)追蹤大量的對(duì)象,所以耗時(shí)較高。并發(fā)清理,又需要把垃圾對(duì)象從各種隨機(jī)的內(nèi)存位置清理掉,也是比較耗時(shí)的
所以在這兩個(gè)階段,CMS的垃圾回收線程是比較耗費(fèi)CPU資源的。CMS默認(rèn)啟動(dòng)的垃圾回收線程的數(shù)量是(CPU核數(shù) + 3)/ 4
2、Concurrent Mode Failure問題
在并發(fā)清理階段,CMS只不過(guò)是回收之前標(biāo)記好的垃圾對(duì)象,但是這個(gè)階段系統(tǒng)一直在運(yùn)行,可能會(huì)隨著系統(tǒng)運(yùn)行讓一些對(duì)象進(jìn)入老年代,同時(shí)還變成垃圾對(duì)象,這種垃圾對(duì)象是“浮動(dòng)垃圾”。因?yàn)樗m然成為了垃圾,但是CMS只能回收之前標(biāo)記出來(lái)的垃圾對(duì)象,不會(huì)回收他們,需要等到下一次GC的時(shí)候才會(huì)回收他們。所以為了保證在CMS垃圾回收期間,還有一定的內(nèi)存空間讓一些對(duì)象可以進(jìn)入老年代,一般會(huì)預(yù)留一些空間。CMS垃圾回收的觸發(fā)時(shí)機(jī),其中有一個(gè)就是當(dāng)老年代內(nèi)存占用達(dá)到一定比例了,就自動(dòng)執(zhí)行GC。
“-XX:CMSInitiatingOccupancyFaction”參數(shù)可以用來(lái)設(shè)置老年代占用多少比例的時(shí)候觸發(fā)CMS垃圾回收,JDK 1.6里面默認(rèn)的值是92%
也就是說(shuō),老年代占用了92%空間了,就自動(dòng)進(jìn)行CMS垃圾回收,預(yù)留8%的空間給并發(fā)回收期間,系統(tǒng)程序把一些新對(duì)象放入老年代中。
那么如果CMS垃圾回收期間,系統(tǒng)程序要放入老年代的對(duì)象大于了可用內(nèi)存空間,此時(shí)會(huì)如何?
這個(gè)時(shí)候,會(huì)發(fā)生Concurrent Mode Failure,就是說(shuō)并發(fā)垃圾回收失敗了,我一邊回收,你一邊把對(duì)象放入老年代,內(nèi)存都不夠
此時(shí)就會(huì)自動(dòng)用“Serial Old”垃圾回收器替代CMS,就是直接強(qiáng)行把系統(tǒng)程序“Stop the World”,重新進(jìn)行長(zhǎng)時(shí)間的GC Roots追蹤,標(biāo)記出來(lái)全部垃圾對(duì)象,不允許新的對(duì)象產(chǎn)生,然后一次性把垃圾對(duì)象都回收掉,完事后再恢復(fù)系統(tǒng)線程
3、內(nèi)存碎片問題
老年代的CMS采用“標(biāo)記-清理”算法,每次都是標(biāo)記出來(lái)垃圾對(duì)象,然后一次性回收掉,這樣會(huì)導(dǎo)致大量的內(nèi)存碎片產(chǎn)生。如果內(nèi)存碎片太多,會(huì)導(dǎo)致后續(xù)對(duì)象進(jìn)入老年代找不到可用的連續(xù)內(nèi)存空間了,然后觸發(fā)Full GC
所以CMS不是完全就僅僅用“標(biāo)記-清理”算法的,因?yàn)樘嗟膬?nèi)存碎片實(shí)際上會(huì)導(dǎo)致更加頻繁的Full GC
CMS有一個(gè)參數(shù)是“-XX:+UseCMSCompactAtFullCollection”,默認(rèn)就打開,意思是在Full GC之后要再次進(jìn)行“Stop the World”,停止工作線程,然后進(jìn)行碎片整理,就是把存活對(duì)象挪到一起,空出來(lái)大片連續(xù)內(nèi)存空間,避免內(nèi)存碎片
還有一個(gè)參數(shù)是“-XX:CMSFullGCsBeforeCompaction”,這個(gè)意思是執(zhí)行多少次Full GC之后再執(zhí)行一次內(nèi)存碎片整理的工作,默認(rèn)是0,意思就是每次Full GC之后都會(huì)進(jìn)行一次內(nèi)存整理
觸發(fā)老年代GC的時(shí)機(jī)
1、老年代可用內(nèi)存小于新生代全部對(duì)象的大小,如果沒開啟空間擔(dān)保參數(shù),會(huì)直接觸發(fā)Full GC,所以一般空間擔(dān)保參數(shù)都會(huì)打開;
2、老年代可用內(nèi)存小于歷次新生代GC后進(jìn)入老年代的平均對(duì)象大小,此時(shí)會(huì)提前Full GC;
3、新生代Minor GC后的存活對(duì)象大于Survivor,那么就會(huì)進(jìn)入老年代,此時(shí)老年代內(nèi)存不足;
4、-XX:CMSInitiatingOccupancyFaction:老年代的已用內(nèi)存大于設(shè)定的閥值,就會(huì)觸發(fā)Full GC;
5、顯示調(diào)用System.gc
ParNew + CMS帶給我們的痛點(diǎn)是什么
Stop the World,這個(gè)是大家最痛的一個(gè)點(diǎn)
無(wú)論是新生代垃圾回收,還是老年代垃圾回收,都會(huì)或多或少產(chǎn)生“Stop the World”現(xiàn)象,對(duì)系統(tǒng)的運(yùn)行是有一定影響的。所以其實(shí)之后對(duì)垃圾回收器的優(yōu)化,都是朝著減少“Stop the World”的目標(biāo)去做的。
在這個(gè)基礎(chǔ)之上,G1垃圾回收器就應(yīng)運(yùn)而生了,他可以提供比“ParNew + CMS”組合更好的垃圾回收的性能
特點(diǎn)
G1垃圾回收器是可以同時(shí)回收新生代和老年代的對(duì)象的,不需要兩個(gè)垃圾回收器配合起來(lái)運(yùn)作,他一個(gè)人就可以搞定所有的垃圾回收。
1、把Java堆內(nèi)存拆分為多個(gè)大小相等的Region
G1也會(huì)有新生代和老年代的概念,但是只不過(guò)是**邏輯上的概念**
也就是說(shuō)新生代可能包含了某些Region,老年代可能包含了某些Region。
2、可以設(shè)置一個(gè)垃圾回收的預(yù)期停頓時(shí)間
也就是說(shuō)比如我們可以指定:希望G1在垃圾回收的時(shí)候,可以保證,在1小時(shí)內(nèi)由G1垃圾回收導(dǎo)致的“Stop the World”時(shí)間,也就是系統(tǒng)停頓的時(shí)間,不能超過(guò)1分鐘,這樣相當(dāng)于我們就可以直接控制垃圾回收對(duì)系統(tǒng)性能的影響
3、Region可能屬于新生代也可能屬于老年代
剛開始Region可能誰(shuí)都不屬于,然后接著就分配給了新生代,然后放了很多屬于新生代的對(duì)象,接著就觸發(fā)了垃圾回收這個(gè)Region,下一次同一個(gè)Region可能又被分配了老年代了,用來(lái)放老年代的長(zhǎng)生存周期的對(duì)象,所以其實(shí)在G1對(duì)應(yīng)的內(nèi)存模型中,Region隨時(shí)會(huì)屬于新生代也會(huì)屬于老年代,所以沒有所謂新生代給多少內(nèi)存,老年代給多少內(nèi)存這一說(shuō)
實(shí)際上新生代和老年代各自的內(nèi)存區(qū)域是不停的變動(dòng)的,由G1自動(dòng)控制
G1是如何做到對(duì)垃圾回收導(dǎo)致的系統(tǒng)停頓可控的?
其實(shí)G1如果要做到這一點(diǎn),他就必須要追蹤每個(gè)Region里的回收價(jià)值,啥叫做回收價(jià)值呢?
他必須搞清楚每個(gè)Region里的對(duì)象有多少是垃圾,如果對(duì)這個(gè)Region進(jìn)行垃圾回收,需要耗費(fèi)多長(zhǎng)時(shí)間,可以回收掉多少垃圾?G1通過(guò)追蹤發(fā)現(xiàn),1個(gè)Region中的垃圾對(duì)象有10MB,回收他們需要耗費(fèi)1秒鐘,另外一個(gè)Region中的垃圾對(duì)象有20MB,回收他們需要耗費(fèi)200毫秒。
然后在垃圾回收的時(shí)候,G1會(huì)發(fā)現(xiàn)在最近一個(gè)時(shí)間段內(nèi),比如1小時(shí)內(nèi),垃圾回收已經(jīng)導(dǎo)致了幾百毫秒的系統(tǒng)停頓了,現(xiàn)在又要執(zhí)行一次垃圾回收,那么必須是回收上圖中那個(gè)只需要200ms就能回收掉20MB垃圾的Region;于是G1觸發(fā)一次垃圾回收,雖然可能導(dǎo)致系統(tǒng)停頓了200ms,但是一下子回收了更多的垃圾,就是20MB的垃圾
所以簡(jiǎn)單來(lái)說(shuō),G1可以做到讓你來(lái)設(shè)定垃圾回收對(duì)系統(tǒng)的影響,他自己通過(guò)把內(nèi)存拆分為大量小Region,以及追蹤每個(gè)Region中可以回收的對(duì)象大小和預(yù)估時(shí)間,最后在垃圾回收的時(shí)候,盡量把垃圾回收對(duì)系統(tǒng)造成的影響控制在你指定的時(shí)間范圍內(nèi),同時(shí)在有限的時(shí)間內(nèi)盡量回收盡可能多的垃圾對(duì)象。這就是G1的核心設(shè)計(jì)思路
如何設(shè)定G1對(duì)應(yīng)的內(nèi)存大小?
G1對(duì)應(yīng)的是一大堆的Region內(nèi)存區(qū)域,每個(gè)Region的大小是一致的,默認(rèn)情況下自動(dòng)計(jì)算和設(shè)置的,可以給整個(gè)堆內(nèi)存設(shè)置一個(gè)大小,比如說(shuō)用“-Xms”和“-Xmx”來(lái)設(shè)置堆內(nèi)存的大小
JVM啟動(dòng)的時(shí)候,發(fā)現(xiàn)使用的是G1垃圾回收器(通過(guò):用“-XX:+UseG1GC”來(lái)指定使用G1垃圾回收器),此時(shí)會(huì)自動(dòng)用堆大小除以2048,JVM最多可以有2048個(gè)Region,然后Region的大小必須是2的倍數(shù),比如說(shuō)1MB、2MB、4MB之類,可以通過(guò)手動(dòng)方式來(lái)指定,則是**“-XX:G1HeapRegionSize“**
剛開始的時(shí)候,默認(rèn)新生代對(duì)堆內(nèi)存的占比是5%,這個(gè)是可以通過(guò)“-XX:G1NewSizePercent”來(lái)設(shè)置新生代初始占比的,其實(shí)維持這個(gè)默認(rèn)值即可
在系統(tǒng)運(yùn)行中,JVM其實(shí)會(huì)不停的給新生代增加更多的Region,但是最多新生代的占比不會(huì)超過(guò)60%,可以通過(guò)“-XX:G1MaxNewSizePercent”,而且一旦Region進(jìn)行了垃圾回收,此時(shí)新生代的Region數(shù)量還會(huì)減少,這些其實(shí)都是動(dòng)態(tài)
新生代還有Eden和Survivor的概念?
G1中雖然把內(nèi)存劃分為很多的 Region,但是其實(shí)還是有新生代、老年代的區(qū)分,而且新生代里還是有Eden和Survivor的劃分
通過(guò)參數(shù),“-XX:SurvivorRatio=8”,可以設(shè)置新生代中80%的Region屬于Eden,兩個(gè)Survivor各自占10%
隨著對(duì)象不停的在新生代里分配,屬于新生代的Region會(huì)不斷增加,Eden和Survivor對(duì)應(yīng)的Region也會(huì)不斷增加
G1的新生代垃圾回收觸發(fā)機(jī)制?
既然G1的新生代也有Eden和Survivor的區(qū)分,那么觸發(fā)垃圾回收的機(jī)制都是類似的,隨著不停的在新生代的Eden對(duì)應(yīng)的Region中放對(duì)象,JVM就會(huì)不停的給新生代加入更多的Region,直到新生代占據(jù)堆大小的最大比例60%。
一旦新生代達(dá)到了設(shè)定的占據(jù)堆內(nèi)存的最大大小60%,這個(gè)時(shí)候還是會(huì)觸發(fā)新生代的GC,G1就會(huì)用之前說(shuō)過(guò)的復(fù)制算法來(lái)進(jìn)行垃圾回收,進(jìn)入一個(gè)“Stop the World”狀態(tài),然后把Eden對(duì)應(yīng)的Region中的存活對(duì)象放入S1對(duì)應(yīng)的Region中,接著回收掉Eden對(duì)應(yīng)的Region中的垃圾對(duì)象,但是這個(gè)過(guò)程跟之前是有區(qū)別的,因?yàn)镚1是可以設(shè)定目標(biāo)GC停頓時(shí)間的,也就是G1執(zhí)行GC的時(shí)候最多可以讓系統(tǒng)停頓多長(zhǎng)時(shí)間,可以通過(guò)“-XX:MaxGCPauseMills”參數(shù)來(lái)設(shè)定,默認(rèn)值是200ms。
那么G1就會(huì)通過(guò)之前說(shuō)的,對(duì)每個(gè)Region追蹤回收他需要多少時(shí)間,可以回收多少對(duì)象來(lái)選擇回收一部分的Region,保證GC停頓時(shí)間控制在指定范圍內(nèi),盡可能多的回收掉一些對(duì)象。
對(duì)象什么時(shí)候進(jìn)入老年代?
可以說(shuō)跟之前幾乎是一樣的,還是這么幾個(gè)條件:
1、對(duì)象在新生代躲過(guò)了很多次的垃圾回收,達(dá)到了一定的年齡了,“-XX:MaxTenuringThreshold”參數(shù)可以設(shè)置這個(gè)年齡,就會(huì)進(jìn)入老年代
2、 動(dòng)態(tài)年齡判定規(guī)則,如果一旦發(fā)現(xiàn)某次新生代GC過(guò)后,存活對(duì)象超過(guò)了Survivor的50%
大對(duì)象Region
在之前,大對(duì)象是直接進(jìn)入老年代,在G1的內(nèi)存模型中,G1提供了專門的Region來(lái)存放大對(duì)象,而不是讓大對(duì)象直接進(jìn)入老年的Region中。
在G1中,大對(duì)象的判定規(guī)則就是一個(gè)大對(duì)象超過(guò)了一個(gè)Region大小的50%,如果每個(gè)Region是2MB,只要一個(gè)大對(duì)象超過(guò)了1MB,就會(huì)被放入大對(duì)象專門的Region中,而且一個(gè)大對(duì)象如果太大,可能會(huì)橫跨多個(gè)Region來(lái)存放在新生代、老年代回收的時(shí)候,會(huì)順帶帶著大對(duì)象Region一起回收
“JVM有哪些常用的功能”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。