jvm

JVM

簡介

JRE由JVM、java core classes、java 平臺組建構成

JVM相當於提供了一個與系統無關的軟件隔離平臺

架構

JVM hotspot架構


java class file    ------->   class load system
                                    |
                                    |
                                    |
running time:  method heap  thread   pc_counter   native內部線程
                                    |
                                    |
excute: jit  gc   <------>  native interface   <----->  native method lib

native method

JAVA實現平臺隔離的關鍵,封裝的是java調用c++的接口,在c++中實現了平臺相關的操作。

native方法是通過java中的JNI實現的。JNI是Java Native Interface的 縮寫。

目前java與dll交互的技術主要有3種:jni,jawin和jacob。

java>jni>jawin>jacob,層層包含關係,可用性外層最好。

native 實例

GC

簡介

garbage collection

concurrent: 併發, 多個線程協同做同一件事情(有狀態)

parallel: 並行, 多個線程各做各的事情(互相間無共享狀態)

分類

上一代的垃圾收集器(串行serial, 並行parallel, 以及CMS)都把堆內存劃分爲固定大小的三個部分: 年輕代(young generation), 年老代(old generation), 以及持久代(permanent generation).

young: eden+survivor space(s0 s1)

old:

permanent

內存放在這三個區域中的一個。

新的垃圾回收器 G1

G1 GC

簡介

G1 (Garbage-First)是一款面向服務器的垃圾收集器,主要針對配備多顆處理器及大容量內存的機器. 以極高概率滿足GC停頓時間要求的同時,還具備高吞吐量性能特徵.

特點

可以像CMS收集器一樣,GC操作與應用的線程一起併發執行
緊湊的空閒內存區間且沒有很長的GC停頓時間.
需要可預測的GC暫停耗時.
不想犧牲太多吞吐量性能.
啓動後不需要請求更大的Java堆.

原理

不同於老的垃圾回收器,只有三個區域,每個heap都放在三個區域中的一個。

G1將每個heap作爲一個獨立區域,然後分別爲他們進行上色,分別問 young, old, permanent

G1標記哪些內存區域是活動的,然後將最空餘的heap進行優先回收,這就是所謂的garbage first: G1.

G1不是實時的,會將目標暫停,同時在這個階段內儘可能的完成收集。

G1收集分爲兩個階段:

併發:concurrent, 與應用線程一起運行, 如: 細化 refinement、標記 marking、清理 cleanup

並行:parallel, 多線程執行, 如: 停止所有JVM線程, stop the world(STW)

G1內存佔用:

如果從 ParallelOldGC 或者 CMS收集器遷移到 G1, 您可能會看到JVM進程佔用更多的內存(a larger JVM process size). 這在很大程度上與 “accounting” 數據結構有關, 如 Remembered SetsCollection Sets.

Remembered Sets 簡稱 RSets, 跟蹤指向某個heap區內的對象引用. 堆內存中的每個區都有一個 RSet. RSet 使heap區能並行獨立地進行垃圾集合. RSets的總體影響小於5%.

Collection Sets 簡稱 CSets, 收集集合, 在一次GC中將執行垃圾回收的heap區. GC時在CSet中的所有存活數據(live data)都會被轉移(複製/移動). 集合中的heap區可以是 Eden, survivor, 和/或 old generation. CSets所佔用的JVM內存小於1%.

推薦使用場景

G1的首要目標是爲需要大量內存的系統提供一個保證GC低延遲的解決方案. 也就是說堆內存在6GB及以上,穩定和可預測的暫停時間小於0.5秒.

如果應用程序具有如下的一個或多個特徵,那麼將垃圾收集器從CMS或ParallelOldGC切換到G1將會大大提升性能.

Full GC 次數太頻繁或者消耗時間太長.
對象分配的頻率或代數提升(promotion)顯著變化.
受夠了太長的垃圾回收或內存整理時間(超過0.5~1秒)
注意: 如果正在使用CMS或ParallelOldGC,而應用程序的垃圾收集停頓時間並不長,那麼繼續使用現在的垃圾收集器是個好主意. 使用最新的JDK時並不要求切換到G1收集器。

G1實際運行過程

G1過程

年輕代收集: 觸發STW(stop the world),將所有年輕代拷貝到新的survivor區域(統一視爲年輕代區域)或者老年代區域,是併發收集的。

存活對象收集: 歸屬在年輕代收集中

老年代收集: 刪除沒有用到的老年帶,把年輕代區域拷貝到老年代區域。

G1命令行與最佳實踐

java -Xmx50m -Xms50m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 hello


關鍵命令行開關

-XX:+UseG1GC - 讓 JVM 使用 G1 垃圾收集器.

-XX:MaxGCPauseMillis=200 - 設置最大GC停頓時間(GC pause time)指標(target). 這是一個軟性指標(soft goal), JVM 會盡力去達成這個目標. 所以有時候這個目標並不能達成. 默認值爲 200 毫秒.

-XX:InitiatingHeapOccupancyPercent=45 - 啓動併發GC時的堆內存佔用百分比. G1用它來觸發併發GC週期,基於整個堆的使用率,而不只是某一代內存的使用比例。值爲 0 則表示“一直執行GC循環)'. 默認值爲 45 (例如, 全部的 45% 或者使用了45%).

最佳實踐

不要設置年輕代的大小(Young Generation Size)

假若通過 -Xmn 顯式地指定了年輕代的大小, 則會干擾到 G1收集器的默認行爲.



什麼是轉移失敗(Evacuation Failure)?

對 survivors 或 promoted objects 進行GC時如果JVM的heap區不足就會發生提升失敗(promotion failure). 堆內存不能繼續擴充,因爲已經達到最大值了. 當使用 -XX:+PrintGCDetails 時將會在GC日誌中顯示 to-space overflow (to-空間溢出)。

這是很昂貴的操作!

GC仍繼續所以空間必須被釋放.
拷貝失敗的對象必須被放到正確的位置(tenured in place).
CSet指向區域中的任何 RSets 更新都必須重新生成(regenerated).
所有這些步驟都是代價高昂的.
如何避免轉移失敗(Evacuation Failure)

要避免避免轉移失敗, 考慮採納下列選項.

增加堆內存大小
增加 -XX:G1ReservePercent=n, 其默認值是 10.
G1創建了一個假天花板(false ceiling),在需要更大 'to-space' 的情況下會嘗試從保留內存獲取(leave the reserve memory free).
更早啓動標記週期(marking cycle)
通過採用 -XX:ConcGCThreads=n 選項增加標記線程(marking threads)的數量.

JVM設置參數

jvm設置參數

發佈了46 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章