JVM(Java虛擬機),最常見的就是HotSpot VM,相信所有Java程序員都知道,它是Sun JDK和OpenJDK中所帶的虛擬機,也是目前使用范圍最廣的Java虛擬機。
JVM堆內(nèi)存和非堆內(nèi)存
JDK1.8開始MetaSpace(元空間)取代(Perm)永久代
官方的說法:“Java 虛擬機具有一個堆(Heap),堆是運行時數(shù)據(jù)區(qū)域,所有類實例和數(shù)組的內(nèi)存均從此處分配。堆是在 Java 虛擬機啟動時創(chuàng)建的。”“在JVM中堆之外的內(nèi)存稱為非堆內(nèi)存(Non-heap memory)”。
Java 虛擬機具有一個堆,堆是運行時數(shù)據(jù)區(qū)域,所有類實例和數(shù)組的內(nèi)存均從此處分配。堆是在 Java 虛擬機啟動時創(chuàng)建的。對象的堆內(nèi)存由稱為垃圾回收器的自動內(nèi)存管理系統(tǒng)回收。
1、Java 內(nèi)存分為3個代:堆內(nèi)存有【New(新生代)、Old(老年代)】,Perm(永久代)
堆內(nèi)存:一般存放new出來的對象,存放數(shù)組等;
非堆內(nèi)存(永久代):存放靜態(tài)變量、常量、方法
2、堆內(nèi)存有:new(新生代)、old(老年代)
①年輕代分為:1個伊甸園區(qū)(eden)、2個存活區(qū)(survivor)
②這2個存活區(qū)大小相等,位置互換(所謂的位置互換:每一次YGC,總會有一個存活區(qū)是空的)
3、new出來的對象優(yōu)先分配在伊甸園區(qū),新的對象不斷進入eden,只有當eden區(qū)滿了后,才觸發(fā)YoungGC;
觸發(fā)YGC時,JVM先判斷對象是不是有引用指向它(通過尋根遍歷,從根節(jié)點進行判斷),然后做2件事:
①如果是沒有引用指向的對象,則當成垃圾回收掉;
②如果是有引用指向的對象,則把該對象放到存活區(qū)(s0或者s1)里;此時eden區(qū)就空了。又可以繼續(xù)放新的對象。eden如果再次滿了,則第二次觸發(fā)YGC。

觸發(fā)YoungGC的過程
4、下圖是第一次觸發(fā)YGC,YGC只會在伊甸園區(qū)觸發(fā),伊甸園區(qū)滿了就觸發(fā)YGC

5、第二次觸發(fā)YGC,會判斷eden的對象是否有引用指向,s0里是否有引用。s0變成了s1,s1成了s0;

6、第三次觸發(fā)YGC:對于eden,如果有引用指向的對象,就繼續(xù)放到存活區(qū)s0;沒有引用指向的對象就當做垃圾回收掉。對于存活區(qū)s1,會被判斷是否有引用指向,然后放入到s0區(qū),s1空了。

6、問:YGC觸發(fā)后,是把所有的有引用的對象都放到S0后,新的對象才能進入eden嗎?
答:YGC觸發(fā)后或者FGC觸發(fā)后,整個java應用程序線程是暫停的(應用程序不干活),只進行垃圾回收。如果這個垃圾回收時間很長,用戶就感覺到慢了,這應該就是影響性能問題的地方。
7、老年代(old):【大對象】和【長期存活的對象】直接進入老年代;
eden放不下這些大對象,【大對象】直接放進老年代;
長期存活的對象:默認年齡等于15(此值可更改),也就是執(zhí)行了15次YGC還存在的對象
第一次出現(xiàn)YGC,此對象就在存活區(qū),此時對象年齡+1,
第二次出現(xiàn)YGC,此對象還在存活區(qū),此時對象年齡再+1,
如此到15次,此對象還在存活區(qū),則放入老年代。

8、Full?GC一般會在3種情況下觸發(fā):
?????①老年代滿的時候觸發(fā)Full?GC(FGC),對整個堆內(nèi)存和非堆內(nèi)存進行垃圾回收。
??FGC一般會用20多秒時間。JVM調(diào)優(yōu)時:盡量減少FGC出現(xiàn)頻率(也是垃圾回收核心原理)
?????②持久代(非堆內(nèi)存)滿的時候,也觸發(fā)FGC
③被顯式調(diào)用(代碼里執(zhí)行system.GC()??Runtime.gc();可以在JVM里disable掉)、?執(zhí)行了悲觀策略(比如jmap和dump的時候)。
觸發(fā)第一次FGC,老年代中的對象沒有被回收徹底,如此5次還是有對象沒有被徹底回收,就會報(out?of?memory)等錯誤。
