對象通常在堆上分配,但JVM支持一種在棧上分配內存的機制。
經過-XX:+DoEscapeAnalysis
開啓逃逸分析
(默認開啓),JVM會針對不會逃逸的對象分配在棧上。好處是,棧能夠自動彈出,不須要垃圾回收參與處理這些對象。html
此外TLAB(Thread Local Allocation Buffer)是一個線程獨佔的堆空間。通常的堆空間是共享的,在內存分配時,多個線程須要同步,但TLAB區域因爲線程獨佔,因此沒必要在分配內存時進行同步。TLAB自己佔用eden區域。java
關於逃逸分析
和TLAB
參見jvm 優化篇-(4)-棧上分配與逃逸分析 -XX:+DoEscapeAnalysis -XX:+UseTLAB -XX:TLABRefillWasteFraction算法
現代垃圾回收的基本算法是標記清除(Mark-Sweep),但依然要面臨內存碎片的問題。JVM採用分代機制解決內存碎片問題。多線程
新生代採用複製算法。新生代的特色是,大部分對象是能夠回收的。新生代區進一步分爲eden區、from區、to區。from區和to區是兩塊大小相同內存區域,有時也叫S0/S1,做用是交換存活對象。新生代內存分配發生在eden區。當新生代須要垃圾回收時,假設此時S0中是上一次GC留下來的存活對象,那麼eden中的存活對象和S0中的對象都將複製到S1(並對齊),而後eden和S0能夠直接清空;下一次垃圾回收時,eden和S1的存活對象複製到S0(並對齊)。因此說S0和S1相互交換存活對象。若是S0和S1沒法容納對象,那麼部分對象將進入老年代區。因爲新生代中大部分對象是能夠回收的,因此採用這種複製算法壓縮內存最爲高效。併發
老年代採用標記壓縮算法。由於老年代活動對象多,垃圾對象少。jvm
G1採用分區算法。分區的思想是將推內存劃分爲多個區,若是每次只收集若干區域,而不是整個堆,能夠有效的控制停頓時間。函數
垃圾回收器經歷了串行、並行(多線程)、併發(不阻塞應用)的發展。參考[深刻JVM讀書筆記(四)——Java的垃圾收集器]性能
早期的垃圾收集器能夠組合使用,以下圖優化
G1收集器的整體效果是好於CMS的,有更好的自我調節能力而G1從JDK9開始纔是默認垃圾回收器。因此JDK8的狀況下,最好主動設置G1垃圾回收器:spa
-XX:+UseG1GC
G1收集器用Region來劃份內存,雖然邏輯上依然保留新生代和老年代,可是新生代和老年代是由若干Region組成的,而且並不必定要求連續。每一個分區Region也不會肯定地爲某個代服務,能夠按需在新生代和老年代之間切換。
18.657: [GC pause (G1 Evacuation Pause) (young) (initial-mark) 26M->24M(32M), 0.0025448 secs] 18.659: [GC concurrent-root-region-scan-start] 18.660: [GC concurrent-root-region-scan-end, 0.0008815 secs] 18.660: [GC concurrent-mark-start] 18.696: [GC concurrent-mark-end, 0.0357099 secs] 18.696: [GC remark, 0.0037490 secs] 18.703: [GC cleanup 24M->24M(32M), 0.0004163 secs] 18.892: [GC pause (G1 Evacuation Pause) (young) 26M->25M(32M), 0.0027587 secs] 19.014: [GC pause (G1 Evacuation Pause) (mixed) 26M->24M(32M), 0.0042025 secs]
上面是一段G1的gc日誌
併發標記可能被young gc和full gc打斷,例以下面的日誌展現了被full gc中斷的concurrent-mark
34.036: [GC concurrent-mark-start] 34.037: [Full GC (Allocation Failure) 31M->31M(32M), 0.0912206 secs] 34.128: [Full GC (Allocation Failure) 31M->31M(32M), 0.0905478 secs] 34.219: [GC concurrent-mark-abort] 34.219: [GC pause (G1 Evacuation Pause) (young) 31M->31M(32M), 0.0084531 secs] 34.228: [GC pause (G1 Evacuation Pause) (young) (initial-mark) 31M->31M(32M), 0.0067091 secs]
總結
選項 | 說明 |
---|---|
-XX:MaxGCPauseMillis | 設置最大GC停頓時間(GC pause time)指標(target). 這是一個軟性指標(soft goal), JVM 會盡可能去達成這個目標. |
-XX:InitiatingHeapOccupancyPercent | 啓動併發GC週期時的堆內存佔用百分比. G1之類的垃圾收集器用它來觸發併發GC週期,基於整個堆的使用率,而不僅是某一代內存的使用比. 值爲 0 則表示"一直執行GC循環". 默認值爲 45 |
-XX:ParallelGCThreads | 設置垃圾收集器在並行階段使用的線程數,默認值隨JVM運行的平臺不一樣而不一樣 |
jstat -gc <pid>
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT 1088.0 1088.0 0.0 117.2 8704.0 8641.6 21888.0 21888.0 24832.0 24320.1 2560.0 2340.1 26 0.134 13 0.810 0.944
年輕代垃圾回收次數
年輕代垃圾回收消耗時間
老年代垃圾回收次數
老年代垃圾回收消耗時間
查看進程的jvm flag
。例如,驗證DoEscapeAnalysis
默認是開啓的
$ jinfo -flag DoEscapeAnalysis 6953 -XX:+DoEscapeAnalysis
也能夠動態修改部分參數
$ jinfo -flag +PrintGCDetails 6953