Java 垃圾回收機制---generation演算法
jvm中垃圾回收的演算法有許多,這篇主要介紹generration演算法
一.原理
首先每個物件的生存週期是不同的,所以generation演算法將不同物件採用不同的回收策略。
年輕代:年輕代就是為了快速清理掉那些生存週期短的物件而設立的,年輕代分為三個模組,一個eden區,兩個survivor區(survivor0和survivor1),它們記憶體按8:1:1分配,一個新的物件建立首先在eden區,年輕代的回收叫做minor GC,在回收時將eden區中存活的物件複製到survivor0區中,讓後清空eden區。當survivor0區的記憶體被存滿時,eden區和survivor0區將全部存活的物件存入survivor1區。然後將現在的survivor0區和eden區清空,之後現在的survivor1區與survivor0區交換,後隊變前隊一直迴圈,直到回收時當時的survivor1區存不下當時的survivor0+eden區的存活物件時就將存活物件放入老年代。
老年代:當物件在年輕代經歷過次次歷練後,他終於存活到了老年區,所以老年代中的物件大多都是一些生命週期比較長的物件,老年代也比年輕代分到到的記憶體要大,預設是1:2。當老年代記憶體也存滿時就會觸發一次full GC或者叫major GC也就是對年輕代老年代都進行回收。
持久代:用於存放靜態檔案,如Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應用可能動態生成或者呼叫一些class,例如Hibernate 等,在這種時候需要設定一個比較大的持久代空間來存放這些執行過程中新增的類。
GC的執行機制
由於物件進行了分代處理,因此垃圾回收區域、時間也不一樣。GC有兩種型別:Scavenge GC和Full GC。
Scavenge GC
一般情況下,當新物件生成,並且在Eden申請空間失敗時,就會觸發Scavenge GC,對Eden區域進行GC,清除非存活物件,並且把尚且存活的物件移動到Survivor區。然後整理Survivor的兩個區。這種方式的GC是對年輕代的Eden區進行,不會影響到年老代。因為大部分物件都是從Eden區開始的,同時Eden區不會分配的很大,所以Eden區的GC會頻繁進行。因而,一般在這裡需要使用速度快、效率高的演算法,使Eden去能儘快空閒出來。
Full GC
對整個堆進行整理,包括Young、Tenured和Perm。Full GC因為需要對整個對進行回收,所以比Scavenge GC要慢,因此應該儘可能減少Full GC的次數。在對JVM調優的過程中,很大一部分工作就是對於FullGC的調節。有如下原因可能導致Full GC:
1.年老代(Tenured)被寫滿
2.持久代(Perm)被寫滿
3.System.gc()被顯示呼叫
4.上一次GC之後Heap的各域分配策略動態變化
GC收集器:
新生代收集器使用的收集器:Serial、PraNew、Parallel Scavenge
老年代收集器使用的收集器:Serial Old、Parallel Old、CMS
Serial收集器(複製演算法)
新生代單執行緒收集器,標記和清理都是單執行緒,優點是簡單高效。
Serial Old收集器(標記-整理演算法)
老年代單執行緒收集器,Serial收集器的老年代版本。
ParNew收集器(停止-複製演算法)
新生代收集器,可以認為是Serial收集器的多執行緒版本,在多核CPU環境下有著比Serial更好的表現。
Parallel Scavenge收集器(停止-複製演算法)
並行收集器,追求高吞吐量,高效利用CPU。吞吐量一般為99%, 吞吐量= 使用者執行緒時間/(使用者執行緒時間+GC執行緒時間)。適合後臺應用等對互動相應要求不高的場景。
Parallel Old收集器(停止-複製演算法)
Parallel Scavenge收集器的老年代版本,並行收集器,吞吐量優先
CMS(Concurrent Mark Sweep)收集器(標記-清理演算法)
高併發、低停頓,追求最短GC回收停頓時間,cpu佔用比較高,響應時間快,停頓時間短,多核cpu 追求高響應時間的選擇