更新時(shí)間:2020-04-17 14:56:42 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽3035次
java內(nèi)存區(qū)域和內(nèi)存溢出
HotSpotVM是SunJDK和OpenJDK中所帶的虛擬機(jī),也是目前使用范圍最廣的java虛擬機(jī)。
如果一段java方法被調(diào)用次數(shù)達(dá)到一定程度,就會(huì)被判定為熱代碼交給JIT編譯器即時(shí)編譯為本地代碼,提供運(yùn)行速度,這就是HotSpot虛擬機(jī)名稱的由來(lái)。
一、內(nèi)存區(qū)域構(gòu)成
1、程序計(jì)數(shù)器
線程私有的內(nèi)存。
在虛擬機(jī)的概念模型里,字節(jié)碼解釋器工作時(shí)就是通過(guò)改變這個(gè)計(jì)數(shù)器的值來(lái)選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、異常處理、線程恢復(fù)都需要依賴這個(gè)計(jì)數(shù)器來(lái)完成。
為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要有一個(gè)獨(dú)立的程序計(jì)數(shù)器,各條線程之間計(jì)數(shù)器互不影響,獨(dú)立存儲(chǔ)。
消耗內(nèi)存很少,可以忽略。
2、java虛擬機(jī)棧
線程私有的內(nèi)存,生命周期和線程相同。常有人把內(nèi)存分為堆和棧,這個(gè)棧就是虛擬機(jī)棧,或者虛擬機(jī)棧中的局部變量表部分。
局部變量表存放了各種基本數(shù)據(jù)類型、對(duì)象引用和returnAddress(字節(jié)碼指令的地址)
3、本地方法棧
與虛擬機(jī)棧作用相似。區(qū)別是本地方法棧為虛擬機(jī)執(zhí)行java方法服務(wù),而本地方法棧則為虛擬機(jī)使用到的Native方法服務(wù),即由非java語(yǔ)言實(shí)現(xiàn)的方法。
4、java堆
所有線程共享,虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。
堆是java虛擬機(jī)所管理的內(nèi)存中最大的一塊。唯一目的是存放對(duì)象實(shí)例,幾乎所有對(duì)象實(shí)例都在這里分配。
如果堆中沒(méi)有內(nèi)存來(lái)完成實(shí)例分配,且不可擴(kuò)展將會(huì)拋出OutOfMemoryError。
通過(guò)-Xmx和-Xms控制堆內(nèi)存最大值最小值
5、方法區(qū)
線程共享的內(nèi)存區(qū)域,用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。很多人習(xí)慣把Hotspot虛擬機(jī)中的方法區(qū)成為永久代,因?yàn)?/p>
GC很少出現(xiàn)在這個(gè)區(qū)域。方法區(qū)無(wú)法滿足內(nèi)存分配需求時(shí)會(huì)跑出OutOfMemoryError。
使用動(dòng)態(tài)代理或CGLib這類字節(jié)碼技術(shù)時(shí),需要消耗很大的方法區(qū)來(lái)保證動(dòng)態(tài)生成的Class能加載入內(nèi)存。
通過(guò)MaxPermSize控制方法區(qū)容量
6、運(yùn)行時(shí)常量池
運(yùn)行時(shí)常量池是方法區(qū)的一部分
二、內(nèi)存溢出
Hotspot虛擬機(jī)中,對(duì)象在內(nèi)存中存儲(chǔ)的布局可以分為3塊區(qū)域:對(duì)象頭(Header)、實(shí)例數(shù)據(jù)(InstanceData)和對(duì)齊填充(Padding)
1、堆溢出
java.lang.OutOfMemoryError:javaheapspace
2、虛擬機(jī)棧和本地方法棧溢出
java.lang.StackOverflowError
1
3、方法區(qū)和運(yùn)行時(shí)常量池溢出
java.lang.OutOfMemoryError:PermGenspace
1
垃圾收集算法和內(nèi)存分配策略
主要是為了解決兩個(gè)問(wèn)題:內(nèi)存分配與內(nèi)存回收
一、垃圾收集算法
1、標(biāo)記-清除算法
首先標(biāo)記出需要回收的對(duì)象,標(biāo)記完成后統(tǒng)一回收。標(biāo)記清除效率較低,而且會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片。
2、復(fù)制算法
現(xiàn)在的商業(yè)虛擬機(jī)都采用這種收集算法來(lái)回收新生代。將內(nèi)存分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor。
當(dāng)回收時(shí)將Eden和Survior中還存活的對(duì)象一次性的復(fù)制到另一塊Survivor空間上,最后清理掉Eden和剛才用過(guò)的Survivor空間。
Hotspot虛擬機(jī)默認(rèn)Eden和Survivor大小比例是8:1,也就是說(shuō)每次新生代中可用的內(nèi)存空間為整個(gè)新生代容量的90%,只有10%的內(nèi)存會(huì)被浪費(fèi)。
如果Survivor空間不夠用時(shí),需要依賴?yán)夏甏M(jìn)行分配擔(dān)保。
內(nèi)存的分配擔(dān)保就好像我們?nèi)ャy行貸款,如果信譽(yù)良好,銀行會(huì)默認(rèn)我們會(huì)如期還款,只需要有一個(gè)擔(dān)保人保證如果不能還,可以從他賬戶里扣錢,這樣對(duì)銀行就沒(méi)有風(fēng)險(xiǎn)了。
如果另外一塊Survivor空間沒(méi)有足夠空間存放上一次新生代收集下來(lái)的存活對(duì)象,這些對(duì)象直接通過(guò)分配擔(dān)保機(jī)制進(jìn)入老年代。
3、標(biāo)記-整理算法
復(fù)制算法在對(duì)象存活率較高時(shí)要進(jìn)行較多的復(fù)制操作,效率會(huì)降低。老年代采用這種算法,與標(biāo)記清除不同的時(shí),不是直接堆可回收的對(duì)象進(jìn)行清理,而是讓所有存活的對(duì)象
向一端移動(dòng),然后直接清理掉邊界以外的內(nèi)存。
4、分代收集算法
一般把java堆分為新生代和老年代,新生代中每次垃圾收集都發(fā)現(xiàn)有大批對(duì)象死去,只有少量存活,那就選用復(fù)制算法,老年代因?yàn)閷?duì)象存活率高,沒(méi)有額外空間對(duì)他進(jìn)行
內(nèi)存擔(dān)保,必須使用標(biāo)記-清理或標(biāo)記-整理算法
二、內(nèi)存分配與回收策略

1、對(duì)象優(yōu)先在Eden分配
-XX:+PrintGCDetails告訴虛擬機(jī)在發(fā)生垃圾收集行為時(shí)打印內(nèi)存回收日志,并且在進(jìn)程退出時(shí)輸出當(dāng)前的內(nèi)存各區(qū)域分配情況。
上面的設(shè)置可以限制java堆大小為20M不可擴(kuò)展,其中新生代老年代大小分別為10M
2、大對(duì)象直接進(jìn)入老年代
經(jīng)常出現(xiàn)大對(duì)象容易導(dǎo)致內(nèi)存還有不少空間時(shí)就提前觸發(fā)GC以獲取足夠多的連續(xù)空間來(lái)安置它們,寫(xiě)程序時(shí)要盡量避免,更要避免短命大對(duì)象。
虛擬機(jī)提供一個(gè)-XX:PretenureThreshold參數(shù),上面的配置大于3M的對(duì)象直接在老年代分配,這樣做的目的是避免在Eden區(qū)和兩個(gè)Survivor區(qū)之間發(fā)生大量的內(nèi)存復(fù)制。
根據(jù)內(nèi)存擔(dān)保,Survivor區(qū)無(wú)法容納的對(duì)象會(huì)直接進(jìn)入到老年代。
3、長(zhǎng)期存活的對(duì)象將進(jìn)入老年代
對(duì)象在Survivor區(qū)每熬過(guò)一次GC年齡就增加一歲,當(dāng)增加到一定程度(默認(rèn)是15歲),就會(huì)晉升到老年代中。老年代做擔(dān)保時(shí)需要老年代有足夠多的空間,通過(guò)觸發(fā)FullGC來(lái)收集。
虛擬機(jī)性能監(jiān)控命令與可視化工具
命令行
jps虛擬機(jī)進(jìn)程狀況工具
jstat用于監(jiān)視虛擬機(jī)各種運(yùn)行狀態(tài)信息的命令行工具
jstack用于生成虛擬機(jī)當(dāng)前時(shí)刻的線程快照,目的是定位線程長(zhǎng)時(shí)間卡頓的原因
可視化工具
JConsole

以上就是動(dòng)力節(jié)點(diǎn)java培訓(xùn)機(jī)構(gòu)的小編針對(duì)“Java基礎(chǔ)學(xué)習(xí):java虛擬機(jī)內(nèi)存管理”的內(nèi)容進(jìn)行的回答,希望對(duì)大家有所幫助,如有疑問(wèn),請(qǐng)?jiān)诰€咨詢,有專業(yè)老師隨時(shí)為你服務(wù)。
相關(guān)閱讀
Java實(shí)驗(yàn)班
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
Java就業(yè)班
有基礎(chǔ) 直達(dá)就業(yè)
Java夜校直播班
業(yè)余時(shí)間 高薪轉(zhuǎn)行
Java在職加薪班
工作1~3年,加薪神器
Java架構(gòu)師班
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問(wèn)老師會(huì)電話與您溝通安排學(xué)習(xí)