
根據(jù)JVM規(guī)范,JVM 內(nèi)存共分為虛擬機(jī)棧,堆,方法區(qū),程序計(jì)數(shù)器,本地方法棧五個(gè)部分。
程序計(jì)數(shù)器(線程私有):
是當(dāng)前線程鎖執(zhí)行字節(jié)碼的行號(hào)治時(shí)期,每條線程都有一個(gè)獨(dú)立的程序計(jì)數(shù)器,這類內(nèi)存也稱為“線程私有”的內(nèi)存。正在執(zhí)行java方法的話,計(jì)數(shù)器記錄的是虛擬機(jī)字節(jié)碼指令的地址(當(dāng)前指令的地址)。如果是Natice方法,則為空。
java 虛擬機(jī)棧
也是線程私有的。
每個(gè)方法在執(zhí)行的時(shí)候也會(huì)創(chuàng)建一個(gè)棧幀,存儲(chǔ)了局部變量,操作數(shù),動(dòng)態(tài)鏈接,方法返回地址。
每個(gè)方法從調(diào)用到執(zhí)行完畢,對(duì)應(yīng)一個(gè)棧幀在虛擬機(jī)棧中的入棧和出棧。
通常所說(shuō)的棧,一般是指在虛擬機(jī)棧中的局部變量部分。
局部變量所需內(nèi)存在編譯期間完成分配,
如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,則StackOverflowError。
如果虛擬機(jī)棧可以動(dòng)態(tài)擴(kuò)展,擴(kuò)展到無(wú)法申請(qǐng)足夠的內(nèi)存,則OutOfMemoryError。
本地方法棧(線程私有)
和虛擬機(jī)棧類似,主要為虛擬機(jī)使用到的Native方法服務(wù)。也會(huì)拋出StackOverflowError 和OutOfMemoryError。
Java堆(線程共享)
被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)的時(shí)候創(chuàng)建,用于存放對(duì)象實(shí)例。
對(duì)可以按照可擴(kuò)展來(lái)實(shí)現(xiàn)(通過(guò)-Xmx 和-Xms 來(lái)控制)
當(dāng)隊(duì)中沒有內(nèi)存可分配給實(shí)例,也無(wú)法再擴(kuò)展時(shí),則拋出OutOfMemoryError異常。
方法區(qū)(線程共享)
被所有方法線程共享的一塊內(nèi)存區(qū)域。
用于存儲(chǔ)已經(jīng)被虛擬機(jī)加載的類信息,常量,靜態(tài)變量等。
這個(gè)區(qū)域的內(nèi)存回收目標(biāo)主要針對(duì)常量池的回收和堆類型的卸載。

概述:棧內(nèi)存針對(duì)的是每一個(gè)線程,一個(gè)線程一個(gè)棧,棧中的局部變量表中的對(duì)象存放的是該對(duì)象在堆中的內(nèi)存地址;方法區(qū)中主要存放:常量+靜態(tài)變量+類元信息;方法區(qū)中的靜態(tài)變量對(duì)象存放的是該靜態(tài)變量對(duì)象在堆內(nèi)存中的地址。




概述:堆內(nèi)存分為2大塊,年輕代,老年代,年輕代又分為:eden區(qū),survivor區(qū)(from,to),默認(rèn)的jvm虛擬機(jī),將堆內(nèi)存分配:年輕代占1/3,eden區(qū)占8/10,from與to區(qū)分別占1/10,老年代占2/3。
流程概述:一個(gè)web應(yīng)用開始運(yùn)行后,新創(chuàng)建的對(duì)象會(huì)不斷的進(jìn)入到堆內(nèi)存中,放入到eden區(qū),又叫伊甸園區(qū), 當(dāng)伊甸園區(qū)放滿后,會(huì)觸發(fā)minorGc清理伊甸園區(qū)中的垃圾對(duì)象(垃圾對(duì)象指在堆中沒有指針指向的對(duì)象),將未被清理的對(duì)象放入Survivor區(qū)中的from區(qū),之后再次來(lái)了新的對(duì)象就進(jìn)伊甸園區(qū),當(dāng)伊甸園區(qū)滿了,就再次進(jìn)行minorGc,清除伊甸園區(qū)的垃圾對(duì)象,這個(gè)時(shí)候?qū)rom區(qū)也進(jìn)行一次清除,并將from區(qū)中未被清除的對(duì)象放入到to區(qū),將伊甸園區(qū)中未被清除的對(duì)象也放入to區(qū)中,之后那一塊區(qū)域有對(duì)象就清除那一塊區(qū)域,并將未被清除的放入沒有對(duì)象的那一塊。當(dāng)一個(gè)對(duì)象經(jīng)歷了15次Gc未被清除會(huì)放入到老年代,當(dāng)然,還有一些對(duì)象也會(huì)被之間放入到老年代,當(dāng)老年代滿了后,會(huì)進(jìn)行Full Gc 。
使用jdk 自帶的jvm監(jiān)視工具 jvisualvm 進(jìn)行調(diào)優(yōu)
所謂的jvm的調(diào)優(yōu) 調(diào)的是什么?
jvm在執(zhí)行Full GC的時(shí)候 都會(huì)去?STW(STOPWORLD) 停止世界,用戶會(huì)感覺到1到兩秒的卡頓
所以我們調(diào)優(yōu)的目的是為了讓GC的次數(shù)減少,讓GC的速度(STW)加快? ?
java -Xms3072M -Xmn2048M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -jar xxxxx.jar
上述優(yōu)化命令 分配堆內(nèi)存3G 分配年輕代 2G 此時(shí) eden(伊甸園)區(qū) 占1.6G survior區(qū)占400M 其中 from去200M to區(qū)200M? 棧內(nèi)存 1M? 老年代占1G? 元空間又叫方法區(qū) 占256M 、
備注
java -Xms2048M -Xmn1024M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -jar C:\Users\Administrator\Desktop\bmone-server-1.0-SNAPSHOT.jar
minor gc 時(shí)清理對(duì)象會(huì)根據(jù)gcroots根來(lái)清理垃圾對(duì)象。
GcRoots根節(jié)點(diǎn):線程棧的本地變量,靜態(tài)變量,本地方法棧的變量等等。
將GcRoots對(duì)象作為起點(diǎn),從這些節(jié)點(diǎn)開始向下搜索索引引用的對(duì)象,找到的對(duì)象都標(biāo)記為非垃圾對(duì)象,其余標(biāo)記的對(duì)象都是垃圾對(duì)象。
老年代中放的對(duì)象:1.一個(gè)對(duì)象經(jīng)歷了15次Gc? ?2.如果一個(gè)對(duì)象在Survivor區(qū)中的From區(qū)或to區(qū)放不下,或被直接放入老年代? ?3.線程池? 4.緩存對(duì)象(使用靜態(tài)初始化的對(duì)象)? ?5.@service注解? ?6.@Bean注解