JVM中的堆,一般分為三大部分:新生代、老年代、永久代:
1 新生代
主要是用來存放新生的對象。一般占據堆的1/3空間。由於頻繁創建對象,所以新生代會頻繁觸發MinorGC進行垃圾回收。
新生代又分為 Eden區、ServivorFrom、ServivorTo三個區。
Eden區:Java新對象的出生地(如果新創建的對象占用內存很大,則直接分配到老年代)。當Eden區內存不夠的時候就會觸發MinorGC,對新生代區進行一次垃圾回收。
ServivorTo:保留了一次MinorGC過程中的幸存者。
ServivorFrom:上一次GC的幸存者,作為這一次GC的被掃描者。
當JVM無法為新建對象分配內存空間的時候(Eden滿了),Minor GC被觸發。因此新生代空間占用率越高,Minor GC越頻繁。
MinorGC的過程:采用復制算法。
首先,把Eden和ServivorFrom區域中存活的對象復制到ServicorTo區域(如果有對象的年齡以及達到了老年的標准,一般是15,則賦值到老年代區)
同時把這些對象的年齡+1(如果ServicorTo不夠位置了就放到老年區)
然后,清空Eden和ServicorFrom中的對象;最后,ServicorTo和ServicorFrom互換,原ServicorTo成為下一次GC時的ServicorFrom區。
2 老年代
老年代的對象比較穩定,所以MajorGC不會頻繁執行。
在進行MajorGC前一般都先進行了一次MinorGC,使得有新生代的對象晉身入老年代,導致空間不夠用時才觸發。當無法找到足夠大的連續空間分配給新創建的較大對象時也會提前觸發一次MajorGC進行垃圾回收騰出空間。
MajorGC采用標記—清除算法:
首先掃描一次所有老年代,標記出存活的對象
然后回收沒有標記的對象。
MajorGC的耗時比較長,因為要掃描再回收。MajorGC會產生內存碎片,為了減少內存損耗,我們一般需要進行合並或者標記出來方便下次直接分配。
當老年代也滿了裝不下的時候,就會拋出OOM(Out of Memory)異常。
3 永久代
指內存的永久保存區域,主要存放Class和Meta(元數據)的信息。
Class在被加載的時候被放入永久區域。它和和存放實例的區域不同,GC不會在主程序運行期對永久區域進行清理。所以這也導致了永久代的區域會隨着加載的Class的增多而脹滿,最終拋出OOM異常。
在Java8中,永久代已經被移除,被一個稱為“元數據區”(元空間)的區域所取代。
元空間的本質和永久代類似,都是對JVM規范中方法區的實現。不過元空間與永久代之間最大的區別在於:元空間並不在虛擬機中,而是使用本地內存。因此,默認情況下,元空間的大小僅受本地內存限制。類的元數據放入 native memory, 字符串池和類的靜態變量放入java堆中. 這樣可以加載多少類的元數據就不再由MaxPermSize控制, 而由系統的實際可用空間來控制。
Major GC和Full GC區別
Full GC:收集young gen、old gen、perm gen
Major GC:有時又叫old gc,只收集old gen
Minor GC觸發機制:
當年輕代滿時就會觸發Minor GC,這里的年輕代滿指的是Eden代滿,Survivor滿不會引發GC。通過復制算法,回收垃圾。復制算法不會產生內存碎片。
復制算法————————
復制算法將內存划分為兩個區間,在任意時間點,所有動態分配的對象都只能分配在其中一個區間(稱為活動區間),而另外一個區間(稱為空閑區間)則是空閑的。
當有效內存空間耗盡時,JVM將暫停程序運行,開啟復制算法GC線程。接下來GC線程會將活動區間內的存活對象,全部復制到空閑區間,且嚴格按照內存地址依次排列,與此同時,GC線程將更新存活對象的內存引用地址指向新的內存地址。
此時,空閑區間已經與活動區間交換,而垃圾對象現在已經全部留在了原來的活動區間,也就是現在的空閑區間。事實上,在活動區間轉換為空間區間的同時,垃圾對象已經被一次性全部回收。
Major GC的觸發機制:
Major GC又稱為Full GC。當年老代空間不夠用的時候,虛擬機會使用“標記—清除”或者“標記—整理”算法清理出連續的內存空間,分配對象使用。
Full GC觸發機制:
(1)調用System.gc時,系統建議執行Full GC,但是不必然執行
(2)老年代空間不足
(3)方法區空間不足
(4)通過Minor GC后進入老年代的平均大小大於老年代的可用內存
(5)由Eden區、survivor space1(From Space)區向survivor space2(To Space)區復制時,對象大小大於To Space可用內存,則把該對象轉存到老年代,且老年代的可用內存小於該對象大小
當永久代滿時也會引發Full GC,會導致Class、Method元信息的卸載。
虛擬機給每個對象定義了一個對象年齡(Age)計數器。如果對象在 Eden 出生並經過第一次 Minor GC 后仍然存活,並且能被 Survivor 容納的話,將被移動到 Survivor 空間中,並將對象年齡設為 1。對象在 Survivor 區中每熬過一次 Minor GC,年齡就增加 1 歲, 當它的年齡增加到一定程度(默認為 15 歲)時,就會被晉升到老年代中。對象晉升老年代的年齡閾值,可以通過參數 -XX:MaxTenuringThreshold (閾值)來設置。