您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“JVM三大組成部分是什么”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
JVM三大組成部分:類(lèi)加載子系統(tǒng)、運(yùn)行時(shí)數(shù)據(jù)區(qū)、執(zhí)行引擎
1.程序計(jì)數(shù)器(線程私有)
當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。
2.虛擬機(jī)棧(線程私有)
每個(gè)方法被執(zhí)行的時(shí)候都會(huì)同時(shí)創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)
鏈接、方法出口等信息。每一個(gè)方法被調(diào)用直至執(zhí)行完成的過(guò)程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中從入棧到出棧的過(guò)程。
3.本地方法棧(線程私有)
為虛擬機(jī)使用到的Native 方法(底層C編寫(xiě)的方法)服務(wù)。
4.堆(線程共享)
此內(nèi)存區(qū)域的唯一目的就是存放對(duì)象實(shí)例,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存。是垃圾收集器管理的主要區(qū)域,也被稱(chēng)作“GC堆”。
堆大小 = 新生代 + 老年代。其中,堆的大小可以通過(guò)參數(shù) –Xms、-Xmx 、 -Xmn 來(lái)指定。
默認(rèn)的,新生代 ( Young ) 與老年代 ( Old ) 的比例的值為 1:2 ( 該值可以通過(guò)參數(shù) –XX:NewRatio 來(lái)指定 ),即:新生代 ( Young ) = 1/3 的堆空間大小。老年代 ( Old ) = 2/3 的堆空間大小。
其中,新生代 ( Young ) 被細(xì)分為 Eden 和 兩個(gè) Survivor 區(qū)域,這兩個(gè) Survivor 區(qū)域分別被命名為 from 和 to,以示區(qū)分。
默認(rèn)的,Edem : from : to = 8 :1 : 1 ( 可以通過(guò)參數(shù)–XX:SurvivorRatio 來(lái)設(shè)定 ),即: Eden = 8/10 的新生代空間大小,from = to = 1/10 的新生代空間大小。
5.方法區(qū)--JDK1.8改為元空間---非堆內(nèi)存(線程共享)
存儲(chǔ)已被虛擬機(jī)加載的類(lèi)信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。在JDK1.8版本廢棄了永久代,替代的是元空間(MetaSpace),元空間與永久代上類(lèi)似,都是方法區(qū)的實(shí)現(xiàn),他們最大區(qū)別是:元空間并不在JVM中,而是使用本地內(nèi)存。可通過(guò)-XX:PermSize和-XX:MaxPermSize來(lái)指定最小值和最大值。
1.JVM如何確定垃圾?GC ROOT(可達(dá)性分析)
虛擬機(jī)棧(棧幀中的局部變量表)中引用的對(duì)象。
木地方法棧中JNI(Native方法)引用的對(duì)象。
方法區(qū)中的類(lèi)靜態(tài)屬性引用的對(duì)象。
方法區(qū)中常量引用的對(duì)象。
2.JVM調(diào)優(yōu)步驟
2.1 打印GC日志
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps,Tomcat則直接加在JAVA_OPTS變量里
-XX:+HeapDumpOnOutOfMemoryError讓虛擬機(jī)在發(fā)生內(nèi)存溢出時(shí) Dump 出當(dāng)前的內(nèi)存堆轉(zhuǎn)儲(chǔ)快照,以便分析
2.2 分析日志得到關(guān)鍵性指標(biāo)
2.3 分析GC原因,調(diào)優(yōu)JVM參數(shù)
3.JVM查看系統(tǒng)默認(rèn)值
jps:查看進(jìn)程號(hào),jps -l
jinfo:查看默認(rèn)值,jinfo -flag 配置項(xiàng) 進(jìn)程號(hào)/jinfo -flags 進(jìn)程號(hào)
java -XX:+PrintFlagsFinal version
-XX:+PrintFlagsInitial 查看初始值
-XX:+PrintFlagsFinal 查看修改更新
-XX:+PrintCommandLineFlags 默認(rèn)的垃圾回收器
4.JVM常用基本參數(shù)配置
-Xms:初始大小內(nèi)存,默認(rèn)為物理內(nèi)存1/64 等價(jià)于-XX:InitialHeapSize
-Xmx:最大分配內(nèi)存,默認(rèn)為物理內(nèi)存的1/4 等價(jià)于-XX:MaxHeapSize
-Xss:設(shè)置單個(gè)線程棧的大小,一般默認(rèn)為512k~1024k 等價(jià)于-XX:ThreadStackSize
-Xmn:設(shè)置年輕代大小
-XX:MetaspaceSize: 元空間的本質(zhì)和永久代類(lèi)似,都是對(duì)JVM規(guī)范中方法區(qū)的實(shí)現(xiàn)。不過(guò)元空間與永久代之間最大的區(qū)別在于:元空間并不在虛擬機(jī)中,而是使用本地內(nèi)存。因此,默認(rèn)情況下,元空間的大小僅受本地內(nèi)存限制。
-XX:PrintGCDetails:打印GC情況 (查看:名稱(chēng) GC前內(nèi)存占用->GC后內(nèi)存占用 該區(qū)內(nèi)存總大小)
-XX:SurvivorRatio:設(shè)置新生代中eden/ S0/S1空間的比例;默認(rèn)-XX:SurvivorRatio=8,即Eden:S0:S1 = 8:1:1;SurvivorRatio的值就是設(shè)置eden區(qū)的比例占比,S0/S1相同。
-XX:NewRatio:配置年輕代與老年代在堆中的占比,默認(rèn)-XX:NewRatio=2,新生代占1,老年代占2,年輕代占整個(gè)堆的1/3;NewRatio值就是設(shè)置老年代的占比,新生代為1。
-XX:MaxTenuringThreshold:設(shè)置垃圾最大年齡,默認(rèn)為15,且最大不能超過(guò)15。
5.垃圾回收算法和垃圾收集器(GC算法是方法論,垃圾收集器就是算法的落地實(shí)現(xiàn))
四種垃圾回收算法
1.引用計(jì)數(shù):引用時(shí)+1,反之亦然,為0時(shí),表示可回收(循環(huán)引用有問(wèn)題)
2.復(fù)制(Copy):實(shí)際可使用的內(nèi)存空間縮小為原來(lái)的一半(浪費(fèi)空間、耗時(shí))
將內(nèi)存按容量劃分為兩塊,每次只使用其中一塊。當(dāng)這一塊內(nèi)存用完了,就將存活的對(duì)象復(fù)制到另一塊上,然后再把已使用的內(nèi)存空間一次清理掉。這樣使得每次都是對(duì)半個(gè)內(nèi)存區(qū)回收,也不用考慮內(nèi)存碎片問(wèn)題,簡(jiǎn)單高效。缺點(diǎn)需要兩倍的內(nèi)存空間。
3.標(biāo)記清除(Mark Sweep):產(chǎn)生內(nèi)存碎片
GC分為兩個(gè)階段,標(biāo)記和清除。首先標(biāo)記所有可回收的對(duì)象,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象。同時(shí)會(huì)產(chǎn)生不連續(xù)的內(nèi)存碎片。碎片過(guò)多會(huì)導(dǎo)致以后程序運(yùn)行時(shí)需要分配較大對(duì)象時(shí),無(wú)法找到足夠的連續(xù)內(nèi)存,而不得已再次觸發(fā)GC。
4.標(biāo)記整理(Mark Compact):壓縮整理效率低(耗時(shí))
也分為兩個(gè)階段,首先標(biāo)記可回收的對(duì)象,再將存活的對(duì)象都向一端移動(dòng),然后清理掉邊界以外的內(nèi)存。此方法避免標(biāo)記-清除算法的碎片問(wèn)題,同時(shí)也避免了復(fù)制算法的空間問(wèn)題。
擴(kuò):一般年輕代中執(zhí)行GC后,會(huì)有少量的對(duì)象存活,就會(huì)選用復(fù)制算法,只要付出少量的存活對(duì)象復(fù)制成本就可以完成收集。而老年代中因?yàn)閷?duì)象存活率高,沒(méi)有額外過(guò)多內(nèi)存空間分配,就需要使用標(biāo)記-清除或者標(biāo)記-整理算法來(lái)進(jìn)行回收。
四種垃圾回收器
Serial串行:它為單線程環(huán)境設(shè)計(jì)且只使用一個(gè)線程進(jìn)行垃圾回收,會(huì)暫停所有線程。所以不適合生產(chǎn)環(huán)境
Parallel并行:多個(gè)垃圾收集線程并行工作,此時(shí)用戶(hù)線程是暫停的,適用于科學(xué)計(jì)算/大數(shù)據(jù)處理首臺(tái)處理等弱交互場(chǎng)景
CMS并發(fā):用戶(hù)線程和垃圾收集線程同時(shí)執(zhí)行(不一定是并行,可能交替執(zhí)行),不需要停頓用戶(hù)線程(停頓短,可忽略),適用于對(duì)響應(yīng)時(shí)間有要求的場(chǎng)景
* 初始標(biāo)記(Initial Mark)
* 并發(fā)標(biāo)記(Concurrent Mark)
* 重新標(biāo)記(Remark)
* 并發(fā)清除(Concurrent Sweep)
其中,初始標(biāo)記、重新標(biāo)記這兩個(gè)步驟仍然需要暫停應(yīng)用線程。初始標(biāo)記只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象,速度很快,并發(fā)標(biāo)記階段是標(biāo)記可回收對(duì)象,而重新標(biāo)記階段則是為了修正并發(fā)標(biāo)記期間因用戶(hù)程序繼續(xù)運(yùn)作導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄,這個(gè)階段暫停時(shí)間比初始標(biāo)記階段稍長(zhǎng)一點(diǎn),但遠(yuǎn)比并發(fā)標(biāo)記時(shí)間短。
由于整個(gè)過(guò)程中消耗最長(zhǎng)的并發(fā)標(biāo)記和并發(fā)清除過(guò)程收集器線程都可以與用戶(hù)線程一起工作,所以,CMS收集器內(nèi)存回收與用戶(hù)一起并發(fā)執(zhí)行的,大大減少了暫停時(shí)間。
G1:將堆內(nèi)存劃分多個(gè)大小相等的獨(dú)立區(qū)域(Region),并且能預(yù)測(cè)暫停時(shí)間,能預(yù)測(cè)原因它能避免對(duì)整個(gè)堆進(jìn)行全區(qū)收集。G1跟蹤各個(gè)Region里的垃圾堆積價(jià)值大?。ㄋ@得空間大小以及回收所需時(shí)間),在后臺(tái)維護(hù)一個(gè)優(yōu)先列表,每次根據(jù)允許的收集時(shí)間,優(yōu)先回收價(jià)值最大的Region,從而保證了在有限時(shí)間內(nèi)獲得更高的收集效率。
G1收集器工作工程分為4個(gè)步驟,包括:
* 初始標(biāo)記(Initial Mark)
* 并發(fā)標(biāo)記(Concurrent Mark)
* 最終標(biāo)記(Final Mark)
* 篩選回收(Live Data Counting and Evacuation)
初始標(biāo)記與CMS一樣,標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象。并發(fā)標(biāo)記從GC Root開(kāi)始標(biāo)記存活對(duì)象,這個(gè)階段耗時(shí)比較長(zhǎng),但也可以與應(yīng)用線程并發(fā)執(zhí)行。而最終標(biāo)記也是為了修正在并發(fā)標(biāo)記期間因用戶(hù)程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變化的那一部分標(biāo)記記錄。最后在篩選回收階段對(duì)各個(gè)Region回收價(jià)值和成本進(jìn)行排序,根據(jù)用戶(hù)所期望的GC暫停時(shí)間來(lái)執(zhí)行回收。
擴(kuò):
1.G1比較CMS的優(yōu)勢(shì):
1)G1不會(huì)產(chǎn)生內(nèi)存碎片
2)可以精確控制停頓。該收集器是把整個(gè)堆(新生代、老生代)劃分成多個(gè)固定大小的區(qū)域,每次根據(jù)允許停頓的時(shí)間去收集圾最多的區(qū)域
2.垃圾收集器組合:默認(rèn)的垃圾收集器-Parallel Scavenge
6.為什么分代?
將對(duì)象根據(jù)存活概率進(jìn)行分類(lèi),對(duì)存活時(shí)間長(zhǎng)的對(duì)象,放到固定區(qū),從而減少掃描垃圾時(shí)間及Full GC頻率。
針對(duì)分類(lèi)進(jìn)行不同的垃圾回收算法,對(duì)算法揚(yáng)長(zhǎng)避短。注:Full GC會(huì)引發(fā)STW(stop the world)
7.為什么survivor分為兩塊相等大小的幸存空間?
主要為了解決碎片化。如果內(nèi)存碎片化嚴(yán)重,也就是兩個(gè)對(duì)象占用不連續(xù)的內(nèi)存,已有的連續(xù)內(nèi)存不夠新對(duì)象存放,就會(huì)觸發(fā)GC。
8.為什么會(huì)堆內(nèi)存溢出?
在年輕代中經(jīng)過(guò)GC后還存活的對(duì)象會(huì)被復(fù)制到老年代中。當(dāng)老年代空間不足時(shí),JVM會(huì)對(duì)老年代進(jìn)行完全的垃圾回收(Full GC)。
如果GC后,還是無(wú)法存放從Survivor區(qū)復(fù)制過(guò)來(lái)的對(duì)象,就會(huì)出現(xiàn)OOM(Out of Memory)。
OOM(Out of Memory)異常常見(jiàn)有以下幾個(gè)原因:
1)老年代內(nèi)存不足:java.lang.OutOfMemoryError:Javaheapspace
2)永久代內(nèi)存不足:java.lang.OutOfMemoryError:PermGenspace
3)內(nèi)存泄漏:代碼bug,占用內(nèi)存無(wú)法及時(shí)回收。
OOM在這幾個(gè)內(nèi)存區(qū)都有可能出現(xiàn),實(shí)際遇到OOM時(shí),能根據(jù)異常信息定位到哪個(gè)區(qū)的內(nèi)存溢出。
可以通過(guò)添加個(gè)參數(shù)-XX:+HeapDumpOnOutMemoryError,讓虛擬機(jī)在出現(xiàn)內(nèi)存溢出異常時(shí)Dump出當(dāng)前的內(nèi)存堆轉(zhuǎn)儲(chǔ)快照以便事后分析。
9.cpu過(guò)高問(wèn)題排查
故障現(xiàn)象:用戶(hù)反饋網(wǎng)頁(yè)卡頓嚴(yán)重,登錄2分鐘...
9.1.先用top命令查看資源占用情況,找出cpu占比最高的
top
9.2.ps -ef或者jps進(jìn)一步定位進(jìn)程
ps -ef | grep java
9.3.定位到具體線程或者代碼
top -Hp pid
ps -mp pid -o THREAD,tid,time
-m 顯示所有線程
-p 顯示在pid列表中的進(jìn)程
-o 該參數(shù)后是用戶(hù)自定義格式
9.4.將需要的線程ID轉(zhuǎn)換為16進(jìn)制
printf "%x\n" tid
9.5.jstack 打印線程堆棧信息
jstack 進(jìn)程ID | grep 線程id(16進(jìn)制線程ID小寫(xiě)英文) -A60(表示查找到所在行的后60行)
擴(kuò)展
參數(shù)類(lèi)型:1.標(biāo)配,例:java -version ,java -help 2.-X參數(shù)(了解),例:-Xlint解釋執(zhí)行,-Xcomp第一次使用就編譯成本地代碼(先編譯) 3.-XX
finalize: 是一個(gè) java.lang.Object 里的方法 ,當(dāng)一個(gè)對(duì)象被gc時(shí),調(diào)用,可覆蓋該方法,重新給對(duì)象賦值,即不會(huì)被回收。當(dāng)垃圾收集確定沒(méi)有對(duì)對(duì)象的更多引用時(shí),由對(duì)象上的垃圾收集器調(diào)用。一個(gè)子類(lèi)覆蓋finalize方法來(lái)處理系統(tǒng)資源或執(zhí)行其他清理。
“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)容。