原文地址:http://singleant.iteye.com/blog/1308842
JVM的相關知識是學習java高級特性必須要去深入學習的。平時也有一些學習和實踐,不過總結比較少。
今天有時間總結一下最基礎的內存模型和GC策略的知識,在此記錄一下。
hotspot jvm內存模型
1.內存模型
hotspot的內存模型很多地方都有類似總結,我也簡單總結了一下,大概可以用下圖表示:
關於幾個分區的描述定義
1.線程棧:線程創建是會爲每個線程創建一個線程棧,線程棧裏面會爲每個方法調用創建一個棧幀。主要用於保存線程的當前運行狀態。
2.堆:用於存放運行時中生成的新對像。會劃分成新生代和老年代。新生代裏面又劃分成了eden區、存活1區和存活2區。
3.永久區:方法和常量區,用於存放方法字節碼元數據和各種常量。
爲什麼堆會劃分爲新生代和老年代?
基本原理:對於大部分應用,常駐對象不多。因爲大部分存活壽命不長,新生代和老年代的劃分有利於區分對待和縮小垃圾回收範圍。(Most allocated objects are not referenced (considered live) for long, that is, they die young. Few references from older to younger objects exist.)
2.內存相關啓動參數
內存相關常見jvm參數
參數 | 含義 |
-Xms | 最小堆空間 |
-Xmx | 最大堆空間 |
-Xmn | 新生代空間 |
-Xss | 線程棧空間 |
-XX:PermSize=xxx | 永久代空間 |
-XX:MaxPermSize=xxx | 最大永久代空間 |
-XX:SurviorRatio=xxx | 代表eden:s0的比例 |
-XX:NewRatio=xx | 新生代和舊生代的比例. |
-XX:MaxTenuringThreshold。 | 在新生代最大存活次數 |
hotspot 內存垃圾回收策略總結
1.內存回收策略和常見概念
常見內存回收策略可以從以下幾個維度來理解:
1.1 串行&並行
串行:單線程執行內存回收工作。十分簡單,無需考慮同步等問題,但耗時較長,不適合多cpu。
並行:多線程併發進行回收工作。適合多CPU,效率高。
1.2 併發& stop the world
stop the world:jvm裏的應用線程會掛起,只有垃圾回收線程在工作進行垃圾清理工作。簡單,無需考慮回收不乾淨等問題。
併發:在垃圾回收的同時,應用也在跑。保證應用的響應時間。會存在回收不乾淨需要二次回收的情況。
1.3 壓縮&非壓縮©
壓縮:在進行垃圾回收後,會通過滑動,把存活對象滑動到連續的空間裏,清理碎片,保證剩餘的空間是連續的。
非壓縮:保留碎片,不進行壓縮。
copy:將存活對象移到新空間,老空間全部釋放。(需要較大的內存。)
一個垃圾回收算法,可以從上面幾個維度來考慮和設計,而最終產生擁有不同特性適合不同場景的垃圾回收器。
2.HotSpot JVM的YGC&FGC
YGC :對新生代堆進行GC。頻率比較高,因爲大部分對象的存活壽命較短,在新生代裏被回收。性能耗費較小。
FGC :全堆範圍的GC。默認堆空間使用到達80%(可調整)的時候會觸發FGC。以我們生產環境爲例,一般比較少會觸發FGC,有時10天或一週左右會有一次。
3.常見GC算法和jvm參數
3.1.串行垃圾收集器
新生代和老生代因爲結構劃分不一樣,其串行收集器算法也不一樣
新生代串行收集器
採用stop the world策略,步驟大概是:先從eden區掃描,把存活的對象拷貝到to區,如果to區放不下的對象直接拷貝到old區。再從from區掃描存活對象,如果對象存活次數超過閥值的就移到老年區,其他的移到to區。做完之後from和to區概念互換(from和to只是運行時的概念,其實就對應存活1區和存活2區)。
圖形的表示如下:
回收前:
回收後:
老生代串行收集器
老生代垃圾回收主要分爲三個階段 Mark-sweep-compact
Mark :識別哪些是存活的
Sweep : 識別垃圾,並回收
Compact :滑動活動對象並壓縮到連續空間,碎片整理。
串行垃圾回收器在jvm client模式下是默認啓動的。參數 -XX:+UseSerialGC 可以設置垃圾回收策略爲串行。
3.2並行垃圾回收器
主要以下特點:
充分利用CPU
吞吐量優先
和串行一樣,不過是多線程執行,縮短了stop-the-world時間。
-server模式下默認的回收器。參數 -XX:+UseParallelGC 可以設置垃圾回收策略爲並行。
3.3並行壓縮收集器(Parallel Compacting Collector)
只對老生代適用,新生代仍舊和並行垃圾回收器一樣。
其過程大概如下:
標記階段 ,使用多線程對存在引用的對象進行並行標記。
分析階段 ,GC對各個區域進行分析,GC認爲,在經過上次GC後,越左邊的區域,有引用的對象密度要遠遠大於右邊的區域。所以就從左往右分析,當某個區域的密度達到一個值的時候,就認爲這是一個臨界區域,所以這個臨界區域左邊的區域,將不會進行壓縮,而右邊的區域,則會進行壓縮。
壓縮階段 ,多各個需要壓縮的區域進行並行壓縮
參數-XX:+UseParallelOldGC 可以設置老生代垃圾回收策略爲並行壓縮。
3.4 Concurrent Mark-Sweep (CMS) Collector
主要特點
仍舊是老生代適用。
減少停頓,以響應時間爲優先。
只有標記和清除,不會進行會壓縮。
初始標記和清除支持和應用程序併發執行,中間還是會有一re-mark需要stop the world。
參數-XX:+UseConcMarkSweepGC 可以設置老生代垃圾回收策略爲CMS。
3.5 G1垃圾收集器
是在JDK7裏支持的,用於取代CMS。具體具體見:http://docs.oracle.com/javase/7/docs/technotes/guides/vm/G1.html