Java堆從 GC的角度還可以細分為:新生代(Eden區、From Survivor區和 To Survivor區)和老年代。
新生代:
是用來存放新生的對象。一般占據堆的1/3 空間。由於頻繁創建對象,所以新生代會頻繁觸發MinorGC 進行垃圾 回收。新生代又分為Eden 區、ServivorFrom、 ServivorTo 3個區。
Minor GC和Major GC區別:
Minor GC:簡單理解就是發生在年輕代的GC。三步(復制--清空--互換)
Minor GC的觸發條件為:
當產生一個新對象,新對象優先在Eden區分配。如果Eden區放不下這個對象,虛擬機會使用復制算法發生一次Minor GC,清除掉無用對象,同時將存活對象移動到Survivor的其中一個區(fromspace區或者tospace區)。
虛擬機會給每個對象定義一個對象年齡(Age)計數器,對象在Survivor區中每“熬過”一次GC,年齡就會+1。待到年齡到達一定歲數(默認是15歲),虛擬機就會將對象移動到年老代。
如果新生對象在Eden區無法分配空間時,此時發生Minor GC。發生MinorGC,對象會從Eden區進入Survivor區,如果Survivor區放不下從Eden區過來的對象時,此時會使用分配擔保機制將對象直接移動到年老代。
1.第一次Yong GC(Minor GC)后,Eden區還存活的對象復制到Surviver區的“To”區,“From”區還存活的對象也復制到“To”區,
2.再清空Eden區和From區,這樣就等於“From”區完全是空的了,而“To”區也不會有內存碎片產生,
3.等到第二次Yong GC時,“From”區和“To”區角色互換,很好的解決了內存碎片的問題。
Major GC的觸發條件:
Major GC又稱為Full GC。當年老代空間不夠用的時候,虛擬機會使用“標記—清除”或者“標記—整理”算法清理出連續的內存空間,分配對象使用。
老年代:
主要存放應用程序中生命周期長的內存對象。
老年代的對象比較穩定,所以MajorGC不會頻繁執行。在進行MajorGC 前一般都先進行了一次MinorGC,使得有新生代的對象晉身入老年代,導致空間不夠用時才觸發。
當無法找到足夠大的連續空間分配給新創建的較大對象時也會提前觸發一次MajorGC進行垃圾回收騰出空間。
MajorGC采用標記清除算法:首先掃描一次所有老年代,標記出存活的對象,然后回收沒有標記的對象。MajorGC的耗時比較長,因為要掃描再回收。MajorGC 會產生內存碎片,為了減少內存損耗,我們一般需要進行合並或者標記出來方便下次直接分配。當老年代也滿了裝不下的時候,就會拋出OOM (Out of Memory)異常。
永久代:
指內存的永久保存區域,主要存放Class 和Meta (元數據)的信息,Class在被加載的時候被放入永久區域,它和和存放實例的區域不同,GC不會在主程序運行期對永久區域進行清理。所以這也導致了永久代的區域會隨着加載的Class 的增多而脹滿,最終拋出OOM異常。
JAVA8與元數據 :
在Java8 中,永久代已經被移除,被一個稱為“元數據區”(元空間)的區域所取代。
元空間的本質和永久代類似,元空間與永久代之間最大的區別在於:元空間並不在虛擬機中,而是使用本地內存。因此,默認情況下,元空間的大小僅受本地內存限制。
類的元數據放入native memory,字符串池和類的靜態變量放入java 堆中,這樣可以加載多少類的元數據就不再由MaxPermSize控制,而由系統的實際可用空間來控制。