引言:
之前的文章已經提過,java對象實例是存放在堆上的,至於是在伊甸區、存活區還是老年區,這些都是從對象回收(GC)角度來進行的邏輯劃分。所以我們先說對象的回收(GC),然後再依據GC的策略來說明新的對象具體在哪個區生成。
GC(Garbage Collection):
垃圾回收,指的就是jvm佔用內存的回收。那麼需要回答3個問題:
- 哪些內存需要回收?——>可達性分析算法。
- 什麼時候回收?——>簡單的來說,伊甸區的空間不足發生新生代GC(Minor GC),老年代空間不足的時候發生老年代GC(Major GC / Full GC)
- 如何回收?——>通過垃圾回收器,jdk8默認的是UseParallelGC(PS scavenge + Serial Old),還有UseConMarkSweepGC(ParNew + CMS + Serial Old),以及UseG1GC(G1)。
1、可達性分析算法:以一系列成爲“GC Root”的對象最爲起始點,當一個對象沒有到達GC Roots的引用鏈條,就判定這個對象爲可回收的。
GC Roots對象:
- 虛擬機棧(棧幀中的本地變量表)中引用的對象。
- 方法區中類靜態屬性引用的對象。
- 方法區中常量引用的對象。
- 本地方法棧中JNI(即Native方法)引用的對象。
2、垃圾收集算法(分代收集):
- 新生代,對象存活率較低,複製算法。
- 老年代,對象存活率較高,標記-整理算法、標記-清除算法。
3、垃圾收集器:
新生代收集器:
- Serial收集器:採用“複製”算法,暫停用戶線程,單線程收集。
- ParNew收集器:採用“複製”算法,暫停所有用戶線程,採用多線程並行收集。和CMS老年代收集器搭配使用。關注點:GC時用戶線程的停頓時間。
- Parallel Scavenge收集器:採用“複製”算法,和ParNew收集器類似,但關注點不同。關注點:高吞吐量。
老年代收集器:
- Serial Old 收集器:採用“標記-整理”算法,暫停用戶線程,單線程收集。和Parallel Scavenge收集器搭配使用。
- Parallel Old收集器:採用“標記-整理”算法,暫停用戶線程,多線程並行收集。和Parallel Scavenge收集器搭配使用。
- CMS(Concurrent Mark Sweep)收集器:採用“標記-清除”算法,不暫停用戶線程,多線程併發收集。與ParNew收集器搭配使用。
新一代收集器:
G1(Garbage-First)收集器:
- GC工作時爲並行,GC與用戶線程爲併發;
- 可獨立管理整個GC堆,不需要與其他GC收集器配合使用;
- 空間整合:整理上看是“標記-整理”算法實現的,從局部(兩個Region之間)上看是基於“複製”算法實現的。
總結:
- ParallelScavenge關注的是高吞吐量;
- CMS關注的是低停頓時間;
- G1關注的是使用時間相對較短的停頓來達到很高的吞吐量,CMS的替代品,在超大堆上表現優異(eg:8g以上)。
4、GC發生時間:
(1)MinorGC:大多數情況下,對象在新生代Eden區分配。當Eden區沒有足夠空間時,進行一次minorGC。如果是大對象,直接在老年代分配。
(2)FullGC:
a.系統主動調用System.gc(),不一定立即執行;
b.老年代空間不足;
c.方法區空間不足;
d.通過Minor GC後進入老年代的平均大小大於老年代的可用內存;
e.由Eden區、From Space區向To Space區複製時,對象大小大於To Space可用內存,則把該對象轉存到老年代,且老年代的可用內存小於該對象大小。
參考資料:《深入JAVA虛擬機》