一:堆內(nèi)存和非堆內(nèi)存定義
Java虛擬機(jī)具有一個(gè)堆(Heap)嘱根,堆是運(yùn)行時(shí)數(shù)據(jù)區(qū)域顶燕,所有類實(shí)例和數(shù)組的內(nèi)存均從此處分配。堆是Java虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建的。在JVM中堆之外的內(nèi)u你成為非堆內(nèi)存(Non-heap memory)。
堆內(nèi)存以及相應(yīng)垃圾回收算法
1.堆的大小可以固定用僧,也可以擴(kuò)大和縮小责循,堆內(nèi)存不需要是連續(xù)空間糟港。
2.對(duì)象創(chuàng)建后進(jìn)入Eden。年輕代分為Eden和Survivor院仿。Survivor由FromSpace和ToSpace組成秸抚。Eden區(qū)占大容量,Survivor占小容量歹垫,默認(rèn)比例8:1:1剥汤。
MinorGC:采用復(fù)制算法。首先把Eden和ServivorFrom區(qū)域中存活的對(duì)象賦值到ServivorTo區(qū)域(如果對(duì)象年齡達(dá)到老年標(biāo)準(zhǔn)/ServivorTo位置不夠了排惨,則復(fù)制到老年代)吭敢,同時(shí)對(duì)象年齡+1,然后清空Eden和ServivorFrom中的對(duì)象暮芭。然后ServivorTo和ServivorFrom互換鹿驼。
3.老年代
老年代存放生命周期長的內(nèi)存對(duì)象。
老年代對(duì)象相對(duì)穩(wěn)定辕宏,所以不會(huì)頻繁GC畜晰。在進(jìn)行MajorGC前一般都先進(jìn)行一次MinorGC,使新生代的對(duì)象進(jìn)入老年代瑞筐,導(dǎo)致空間不夠用時(shí)才觸發(fā)舷蟀。當(dāng)無法找到足夠大的連續(xù)空間分配給新晉的對(duì)象也會(huì)提前觸發(fā)MajorGC進(jìn)行垃圾回收。
MajorGC:如果使用CMS收集器,采用標(biāo)記-清除算法野宜。首先掃描老年代,標(biāo)記所有可回收對(duì)象魔策,標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記對(duì)象匈子。同時(shí)會(huì)產(chǎn)生不連續(xù)的內(nèi)存碎片。碎片過多會(huì)導(dǎo)致以后程序運(yùn)行需要分配較大對(duì)象時(shí)闯袒,無法找到足夠的連續(xù)內(nèi)存虎敦,而不得已再次出發(fā)GC。否則采用標(biāo)記-壓縮算法政敢。
標(biāo)記-壓縮:在標(biāo)記可回收對(duì)象后其徙,將不可回收對(duì)象移向一端,然后清除標(biāo)記對(duì)象喷户。
當(dāng)老年代也滿了裝不下時(shí)唾那,拋出OOM異常。
二:永久代
內(nèi)存中永久保存的區(qū)域褪尝,主要存放Class和Meta(元數(shù)據(jù))的信息闹获,Class在被加載的時(shí)候被放入永久區(qū)域。他和存放實(shí)例的區(qū)域不同河哑,GC不會(huì)再主程序運(yùn)行期對(duì)永久區(qū)進(jìn)行清理避诽。所以也可可能導(dǎo)致永久代區(qū)域隨著加載Class的增多而脹滿,拋出OOM璃谨。
Java8中沙庐,永久代已經(jīng)被移除,被一個(gè)成為“元數(shù)據(jù)區(qū)”(元空間)的區(qū)域所取代佳吞。
元空間的本質(zhì)與永久代類似拱雏,都是JVM方法區(qū)的實(shí)現(xiàn)。不過元空間使用本地內(nèi)存容达,永久代在JVM虛擬機(jī)中古涧。因此,默認(rèn)情況下花盐,元空間的大小受本地內(nèi)存限制羡滑。類的元數(shù)據(jù)放入native memory,字符串常量池和類的靜態(tài)變量放入java堆中算芯,這樣可以加載多少類的元數(shù)據(jù)就不再由MaxPermSize控制,而是由系統(tǒng)實(shí)際可用空間控制柒昏。
1元空間解決了永久代的OOM問題,元數(shù)據(jù)和class對(duì)象在永久代容易出現(xiàn)性能問題和內(nèi)存溢出熙揍。
2類的方法信息等比較難確定其大小职祷,對(duì)于永久代的大小指定比較困難,小永久代溢出,大老年代溢出有梆。
3永久代會(huì)為GC帶來不必要的復(fù)雜度是尖,回收效率低。
三:堆內(nèi)存參數(shù)調(diào)優(yōu)
1.-Xms 設(shè)置初始分配內(nèi)存大小,默認(rèn)物理內(nèi)存1/64
2.-Xmx 設(shè)置最大分配內(nèi)存泥耀,默認(rèn)物理內(nèi)存1/4
long maxMemory = Runtime.getRuntime().maxMemory(); long totalMemory = Runtime.getRuntime().totalMemory(); System.out.println("最大分配內(nèi)存"+maxMemory/(double)1024/1024+"MB "+maxMemory/(double)1024/1024/1024+"GB"); System.out.println("默認(rèn)分配內(nèi)存"+totalMemory/(double)1024/1024+"MB "+totalMemory/(double)1024/1024/1024+"GB");
四:比例
新生代 ( Young ) 與老年代 ( Old ) 的比例的值為 1:2 ( 該值可以通過參數(shù) –XX:NewRatio 來指定 )饺汹,即:新生代 ( Young ) = 1/3 的堆空間大小。老年代 ( Old ) = 2/3 的堆空間大小痰催。其中兜辞,新生代 ( Young ) 被細(xì)分為 Eden 和 兩個(gè) Survivor 區(qū)域,這兩個(gè) Survivor 區(qū)域分別被命名為 from 和 to夸溶,以示區(qū)分逸吵。Eden : from : to = 8 : 1 : 1 ( 可以通過參數(shù) –XX:SurvivorRatio 來設(shè)定 )。
五:JVM垃圾回收器
一篇很好的博客:https://blog.csdn.net/qq_26525215/article/details/84294481#Serial_11