
一:堆內(nèi)存和非堆內(nèi)存定義
Java虛擬機具有一個堆(Heap),堆是運行時數(shù)據(jù)區(qū)域,所有類實例和數(shù)組的內(nèi)存均從此處分配。堆是Java虛擬機啟動時創(chuàng)建的。在JVM中堆之外的內(nèi)u你成為非堆內(nèi)存(Non-heap memory)。
堆內(nèi)存以及相應(yīng)垃圾回收算法
1.堆的大小可以固定,也可以擴大和縮小,堆內(nèi)存不需要是連續(xù)空間。
2.對象創(chuàng)建后進入Eden。年輕代分為Eden和Survivor。Survivor由FromSpace和ToSpace組成。Eden區(qū)占大容量,Survivor占小容量,默認(rèn)比例8:1:1。
MinorGC:采用復(fù)制算法。首先把Eden和ServivorFrom區(qū)域中存活的對象賦值到ServivorTo區(qū)域(如果對象年齡達到老年標(biāo)準(zhǔn)/ServivorTo位置不夠了,則復(fù)制到老年代),同時對象年齡+1,然后清空Eden和ServivorFrom中的對象。然后ServivorTo和ServivorFrom互換。
3.老年代
老年代存放生命周期長的內(nèi)存對象。
老年代對象相對穩(wěn)定,所以不會頻繁GC。在進行MajorGC前一般都先進行一次MinorGC,使新生代的對象進入老年代,導(dǎo)致空間不夠用時才觸發(fā)。當(dāng)無法找到足夠大的連續(xù)空間分配給新晉的對象也會提前觸發(fā)MajorGC進行垃圾回收。
MajorGC:如果使用CMS收集器,采用標(biāo)記-清除算法。首先掃描老年代,標(biāo)記所有可回收對象,標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記對象。同時會產(chǎn)生不連續(xù)的內(nèi)存碎片。碎片過多會導(dǎo)致以后程序運行需要分配較大對象時,無法找到足夠的連續(xù)內(nèi)存,而不得已再次出發(fā)GC。否則采用標(biāo)記-壓縮算法。
標(biāo)記-壓縮:在標(biāo)記可回收對象后,將不可回收對象移向一端,然后清除標(biāo)記對象。
當(dāng)老年代也滿了裝不下時,拋出OOM異常。
二:永久代
內(nèi)存中永久保存的區(qū)域,主要存放Class和Meta(元數(shù)據(jù))的信息,Class在被加載的時候被放入永久區(qū)域。他和存放實例的區(qū)域不同,GC不會再主程序運行期對永久區(qū)進行清理。所以也可可能導(dǎo)致永久代區(qū)域隨著加載Class的增多而脹滿,拋出OOM。
Java8中,永久代已經(jīng)被移除,被一個成為“元數(shù)據(jù)區(qū)”(元空間)的區(qū)域所取代。
元空間的本質(zhì)與永久代類似,都是JVM方法區(qū)的實現(xiàn)。不過元空間使用本地內(nèi)存,永久代在JVM虛擬機中。因此,默認(rèn)情況下,元空間的大小受本地內(nèi)存限制。類的元數(shù)據(jù)放入native memory,字符串常量池和類的靜態(tài)變量放入java堆中,這樣可以加載多少類的元數(shù)據(jù)就不再由MaxPermSize控制,而是由系統(tǒng)實際可用空間控制。
1元空間解決了永久代的OOM問題,元數(shù)據(jù)和class對象在永久代容易出現(xiàn)性能問題和內(nèi)存溢出。
2類的方法信息等比較難確定其大小,對于永久代的大小指定比較困難,小永久代溢出,大老年代溢出。
3永久代會為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 和 兩個 Survivor 區(qū)域,這兩個 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