前言
本身在閱讀《深刻理解Java虛擬機》後作了部分的整理,內容有些是來自網絡,若有侵權,請聯繫郵箱:nezhaxiaozi@qq.comjava
本書第一次閱讀,因此並無全篇通讀,主要的閱讀的章節是git
- 第2章 Java內存區域與內存溢出異常
- 第3章 Java垃圾回收機器與內存分配策略
- 第4章 JVM性能監控與故障處理工具
- 第7章 虛擬機類加載機制
總之此書很值得一讀,無論是理解JVM內存模型或者GC的機制及怎麼去JVM調優這本書上寫的仍是挺全面的。程序員
第2章 Java內存區域與內存溢出異常
概述
對於Java程序員來講,在虛擬機自動內存管理機制下,不須要爲new操做去寫配對的delete/free代碼,不容易出現內存泄漏。可是若是出現內存泄漏問題,若是不瞭解虛擬機的機制,便難以定位。github
運行時數據區域
下圖是Java運行時數據區域劃分圖算法
區域 |
是否線程共享 |
是否會內存溢出 |
程序計數器 |
否 |
不會 |
java虛擬機棧 |
否 |
會 |
本地方法棧 |
否 |
會 |
堆 |
是 |
會 |
方法區 |
是 |
會 |
1.程序計數器(線程私有)
- 一塊較小的內存,能夠看做是當前線程所執行的字節碼的行號指示器;
- 在虛擬機概念模型(各類虛擬機實現可能不同)中,字節碼解釋器工做時就是經過改變這個計數器的值來選取下一條須要執行的字節碼指令;
- 程序計數器是屬於線程私有的內存;
- 若是執行的是Java方法,該計數器記錄的是正在執行的虛擬機字節碼指令的地址;若是是Native方法則爲空;
2.Java虛擬機棧(線程私有)
- Java虛擬機棧也是線程私有的;
- 描述的是Java方法執行的內存模型:每一個方法在執行的同時都會建立一個棧幀(Stack Frame)用於存儲
局部變量表
、操做數棧
、動態連接
、方法出口
等信息。每個方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機中入棧到出棧的過程;
- 局部變量表存放了編譯器可知的各類基本數據類型、對象引用和returnAddress類型;其所需的內存空間在編輯期完成分配,不會再運行期改變;
- 可能存在兩種異常:
StackOverflowError
(請求棧深度過大)和OutOfMemoryError
(內存不夠時);
3.本地方法棧
- 與虛擬機棧很是類似,只不過是爲虛擬機使用到的Native方法服務;
- 可能存在兩種異常:StackOverflowError和OutOfMemoryError;
4.Java堆(線程共享)
- Java堆是被全部線程共享的,在虛擬機啓動時建立;
- 此內存區域的惟一目的就是存放對象實例,幾乎全部的對象實例都在這分配;
- 是垃圾收集器管理的主要區域,能夠分爲
新生代
和老年代
;
- 能夠物理不連續,只要邏輯上是連續的便可;
- 若是堆中沒有內存完成實例分配也沒法再擴展時,會拋出OutOfMemoryError異常;
Eden:From Survivor:To Survivor比值爲8:1:1瀏覽器
5.方法區/元空間(永久代)(線程共享)
- 是線程共享的區域;
- 用於存儲已被虛擬機加載的
類信息
、常量
、靜態變量
、即時編譯器編譯後的代碼等數據;
- 該區域對於垃圾收集來講條件比較苛刻,可是仍是很是有必要要進行回收處理;
- 當沒法知足內存分配需求時,將拋出OutOfMemoryError異常;
6.運行時常量池
- 是方法區的一部分;
- Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用於存放編譯器生成的各類字面量和符號引用,這部份內容將在類加載後進入方法區的運行時常量池中存放;
- Java虛擬機規範要求較少,一般還會把翻譯出來的直接引用也存儲在此;
- 另一個重要特徵是具有動態性,能夠在運行期間將新的常量放入池中,如String的intern方法;
- 可能存在的異常:OutOfMemoryError;
7.直接內存
- 並非虛擬機運行時數據區的一部分,也不是Java虛擬機規範中定義的內存區域;
- JDK 1.4的NIO引入了基於通道(Channel)和緩衝區(Buffer)的IO方法,可使用Native函數庫直接分配對外內存,而後經過一個存儲在Java堆中的DirectByteBuffer對象做爲這塊內存的引用進行操做以提高性能;
對象的訪問定位
- 棧上的reference類型在虛擬機規範中只規定了一個指向對象的引用,並無定義這個引用應該經過何種方式去定位、訪問堆棧對象的具體位置,目前主流的方式方式有
句柄
和直接指針
兩種。
- 經過句柄:Java堆中劃出一塊內存做爲句柄池,reference中存儲的就是對象的句柄地址,而句柄中包含了對象實例數據與類型數據各自的具體地址信息。其最大好處就是reference存儲的是穩定的句柄地址,在對象被移動(垃圾收集時移到)只改變實例數據指針,而reference不須要修改;
- 經過直接指針:Java堆對象的佈局中必須考慮若是放置訪問類型數據的相關信息,而reference中存在的直接就是對象地址。其最大好處在於速度更快,節省了一次指針定位的時機開銷。HotSpot採用該方式進行對象訪問,但其餘語言和框架採用句柄的也很是常見。
第3章 Java垃圾回收機器與內存分配策略
概述
思考GC須要完成的3件事情:緩存
- 1.哪些內存須要回收?
- 2.何時回收?
- 3.如何回收?
再回頭看看第二章介紹的Java內存運行時區域的各個部分:安全
- 程序計時器、虛擬機棧、本地方法棧:隨線程而滅,棧幀隨方法而進行出棧和入棧,每個棧幀分配的內存在類結構肯定就已知,所以這幾個區域不須要考慮回收;
- 對於Java堆和方法區,只有程序運行期間才知道會建立哪些對象,內存的分配和回收都是動態的,垃圾收集器所關注的是這部份內存;
判斷Java中對象存活的算法
1.引用計數算法
給對象添加引用計數器,當有地方引用它時就加1,引用失效就減1,爲0時就認爲對象再也不被使用可回收。該算法失效簡單,判斷高效,但並不被主流虛擬機採用,主要緣由是它很難解決對象之間相互循環引用的問題。服務器
2.可達性分析算法
經過一系列的稱爲「GC Roots」的對象做爲起點,從這些節點開始向下搜索,搜索所走過的路徑稱爲引用鏈(Reference Chain),若是一個對象到GC Roots沒有引用鏈相連,則該對象是不可用的。微信
在Java語言中,可做爲GC Roots的對象包括:
- 虛擬機棧(棧幀中的本地變量表)中引用的對象;
- 方法區中類靜態屬性引用的對象;
- 方法區中常量引用的對象;
- 本地方法棧中JNI(即通常說的Native方法)引用的對象;
垃圾收集算法
- 1.標記-清除算法(Mark-Sweep):首先標記出全部須要回收的對象,而後統一回收全部被標記的對象;缺點是效率不高且容易產生大量不連續的內存碎片;
- 複製算法:將可用內存分爲大小相等的兩塊,每次只使用其中一塊;當這一塊用完了,就將還活着的對象複製到另外一塊上,而後把已使用過的內存清理掉。在HotSpot裏,考慮到大部分對象存活時間很短將內存分爲Eden和兩塊Survivor,默認比例爲8:1:1。代價是存在部份內存空間浪費,適合在新生代使用;
垃圾收集器
- 垃圾收集算法是內存回收的方法論,垃圾收集器就是內存回收的具體實現。
- 這裏討論JDK 1.7 Update 14以後的HotSpot虛擬機(此時G1仍處於實驗狀態),包含的虛擬機以下圖所示(存在連線的表示能夠搭配使用):
1.Serial收集器(單線程的收集器)
- 最基本、發展歷史最悠久,在JDK 1.3以前是新生代收集的惟一選擇;
- 是一個單線程(並不是指一個收集線程,而是會暫停全部工做線程)的收集器,採用的是複製算法;
- 如今依然是虛擬機運行在Client模式下的默認新生代收集器,主要就是由於它簡單而高效(沒有線程交互的開銷);
2.ParNew收集器(Serial收集器的多線程版本)
- 其實就是Serial收集器的多線程版本;
- ParNew收集器在單CPU環境中絕對不會有比Serial收集器更好的效果;
- 是許多運行在Server模式下虛擬機首選的新生代收集器,重要緣由就是除了Serial收集器外,只有它能與CMS收集器配合工做;
- 並行(Parallel):指多條垃圾收集線程並行工做,但此時用戶線程仍處於等待狀態;
- 併發(Concurrent):指用戶線程與垃圾收集線程同時執行,用戶線程在繼續執行而垃圾收集程序運行在另一個CPU上;
3.Parallel Scavenge收集器
吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)
- 新生代收集器,使用複製算法,並行的多線程收集器;
- 與CMS關注於盡量縮短垃圾收集時用戶線程停頓時間不一樣,PS的目標是達到一個可控制的吞吐量;
- 高吞吐量能夠高效率利用CPU時間,適合在後臺運算而不須要太多交互的任務;
- -XX:MaxGCPauseMillis參數能夠設置最大停頓時間,而停頓時間縮短是以犧牲吞吐量和新生代空間來換取的;
- 另外它還支持GC自適應的調節策略;
4.Serial Old收集器
- 是Serial收集器的老年代版本,一樣是單線程,使用標記-整理算法;
- 主要是給Client模式下的虛擬機使用的;
- 在Server模式下主要是給JDK 1.5及以前配合Parallel Scavenge使用或做爲CMS收集器的後備預案;
5.Parallel Old收集器
- 是Parallel Scavenge的老年代版本,使用多線程和標記-整理算法;
6.CMS收集器
- 是一種以獲取最短回收停頓時間爲目標的收集器,特別適合互聯網站或者B/S的服務端;
- 它是基於標記-清除 算法實現的,主要包括4個步驟:初始標記(STW-stop the world,只是初始標記一下GC Roots能直接關聯到的對象,速度很快)、併發標記(非STW,執行GC RootsTracing,耗時比較長)、從新標記(STW,修正併發標記期間因用戶程序繼續致使變更的那一部分對象標記)和併發清除(非STW,耗時較長);
- 還有3個明顯的缺點:CMS收集器對CPU很是敏感(佔用部分線程及CPU資源,影響總吞吐量)、沒法處理浮動垃圾(默認達到92%就觸發垃圾回收)、大量內存碎片產生(能夠經過參數啓動壓縮);
7.G1收集器
- 一款面向服務端應用的垃圾收集器,後續會替換掉CMS垃圾收集器;
- 特色:並行與併發(充分利用多核多CPU縮短Stop-The-World時間)、分代收集(獨立管理整個Java堆,但針對不一樣年齡的對象採起不一樣的策略)、空間整合(基於標記-整理)、可預測的停頓(將堆分爲大小相等的獨立區域,避免全區域的垃圾收集);
- 關於Region:新生代和老年代再也不物理隔離,只是部分Region的集合;G1跟蹤各個Region垃圾堆積的價值大小,在後臺維護一個優先列表,根據容許的收集時間優先回收價值最大的Region;Region之間的對象引用以及其餘收集器中的新生代與老年代之間的對象引用,採用Remembered Set來避免全堆掃描;
- 分爲幾個步驟:1.初始標記(標記一下GC Roots能直接關聯的對象並修改TAMS值,須要STW但耗時很短)、2.併發標記(從GC Root從堆中對象進行可達性分析找存活的對象,耗時較長但能夠與用戶線程併發執行)、3.最終標記(爲了修正併發標記期間產生變更的那一部分標記記錄,這一期間的變化記錄在Remembered Set Log裏,而後合併到Remembered Set裏,該階段須要STW可是可並行執行)、4.篩選回收(對各個Region回收價值排序,根據用戶指望的GC停頓時間制定回收計劃來回收);
-
理解GC日誌
詳細的解讀,請查閱本書籍。
- 最前面的數字表明GC發生的時間(虛擬機啓動之後的秒殺);
- 「[GC」和「[Full GC」說明停頓類型,有Full表明的是Stop-The-World的;
- 「[DefNew」、「[Tenured」和「[Perm」表示GC發生的區域;
- 方括號內部的「3324K -> 152K(3712K)」 含義是 「GC前該內存已使用容量 -> GC後該內存區域已使用容量(該區域總容量)」;
- 方括號以外的「3324K -> 152K(11904)」 含義是 「GC前Java堆已使用容量 -> GC後Java堆已使用容量(Java堆總容量)」;
- 再日後「0.0025925 secs」表示該內存區域GC所佔用的時間;
內存分配與回收策略
- 對象優先在新生代分配
- 大對象直接進入老年代
- 長期存活的對象將進入老年代
- 動態對象年齡判斷:若是在Survivor空間中相同年齡全部對象大小總和大於Survivor空間的一半,大於或等於該年齡的對象直接進入老年代;
- 空間分配擔保:發生Minor GC前,虛擬機會先檢查老年代最大可用連續空間是否大於新生代全部對象總空間,若是不成立,虛擬機會查看HandlePromotionFailure設置值是否容許擔保失敗,若是容許繼續檢查老年代最大可用的連續空間是否大於歷次晉升到老年代的平均大小,若是大於會嘗試進行一次Minor GC;若是小於或者不容許冒險,會進行一次Full GC;
第4章 JVM性能監控與故障處理工具
概述
定位問題時,知識和經驗是關鍵基礎、數據(運行日誌、異常堆棧、GC日誌、線程快照、堆轉儲快照)是依據、工具是運用知識處理數據的手段。
JDK命令行工具
1.jps: 虛擬機進程情況工具
- 功能:能夠列出正在運行的虛擬機進程,併線上虛擬機執行的主類名稱及其本地虛擬機惟一ID(LVMID);
- 對於本地虛擬機來講,LVMID和操做系統的進程ID是一致的;
- 其餘的工具一般都須要依賴jps獲取LVMID;
- 主要選項:-q(只輸出LVMID)、-m(輸出傳給main函數的參數)、-l(輸出主類的全名)、-v(輸出虛擬機啓動JVM參數);
2.jstat:虛擬機統計信息監視工具
- 功能:監視虛擬機各類運行狀態信息,包括類裝載、內存、垃圾收集、JIT等;
- 純文本監控首選
3.jinfo:Java配置信息工具
- 功能:實時地查看虛擬機各項參數。雖然jps -v能夠查看虛擬機啓動參數,可是沒法查看一些系統默認的參數。
- 支持運行期修改參數的能力,格式爲「jinfo -flag name=value pid」;
4.jmap:Java內存映像工具
- 功能:用於生成堆轉儲快照(通常稱爲heapdump或dump文件);
- 其餘可生成heapdump的方式:使用參數-XX:+HeapDumpOnOutOfMemoryError;使用參數-XX:+HeapDumpOnCtrlBreak而後使用Ctrl+Break生成;Linux系統使用kill -3生成;
- 另外它還能夠查詢finalize執行隊列、Java堆和永久代的詳細信息;
5.jhat:虛擬機堆轉儲快照分析工具
- 功能:用於分析jmap生成的heapdump。其內置了一個微型的HTTP服務器,能夠在瀏覽器查看分析結果;
- 實際不多用jhat,主要有兩個緣由:一是分析工程會耗用服務器資源;功能相對BisualVM、IBM HeapAnalyzer較爲簡陋
6.jstack:Java堆棧跟蹤工具
- 功能:用於生成虛擬機當前時刻的線程快照(通常稱爲threaddump或javacore文件)。javacore主要目的是定位線程出現長時間停頓的緣由,好比死鎖、死循環、請求外部資源響應長等;
- 另外JDK 1.5後Thread類新增了getAllStackTraces()方法,能夠基於此本身增長管理頁面來分析
7.HSDIS:JIT生成代碼反編譯
- 現代虛擬機的實現慢慢地和虛擬機規範產生差距,若是要分析程序若是執行,最多見的就是經過軟件調試工具(GDB、Windbg等)斷點調試,可是對於Java來講,不少執行代碼是經過JIT動態生成到CodeBuffer中的;
- 功能:HSDIS是官方推薦的HotSpot虛擬機JIT編譯代碼的反彙編工具,它包含在HotSpot虛擬機的源碼中但沒有提供編譯後的程序,能夠本身下載放到JDK的相關目錄裏;
JDK可視化工具
1.JConsole:Java監視與管理控制檯
- 是一種基於JMX的可視化監控和管理工具,它管理部分的功能是針對MBean進行管理,因爲MBean可使用代碼、中間件服務器或者全部符合JMX規範的軟件進行訪問,所以這裏着重介紹JConsole的監控功能;
- 經過jconsole命令啓動JConsole後,會自動搜索本機全部虛擬機進程。另外還支持遠程進程的監控;
- 進入主界面,支持查看如下標籤頁:概述、內存、線程、類、VM摘要和MBean;
2.VisualVM:多合一故障處理工具
- 目前爲止JDK發佈的功能最強調的運行監控和故障處理程序,另外還支持性能分析;
- VisualVM還有一個很大的優勢:不須要被監視的程序基於特殊Agent運行,對應用程序的實際性能影響很小,可直接應用在生成環境中;
- VisualVM基於NetBeans平臺開發,具有插件擴展功能的特性,基於插件能夠作到:顯示虛擬機進程以及進程配置、環境信息(jps、jinfo)、監視應用程序的CPU、GC、堆、方法區以及線程的信息(jstat、jstack)、dump以及分析堆轉儲快照(jmap、jhat)、方法級的程序運行性能分析,找出被調用最多運行時間最長的方法、離線程序快照(收集運行時配置、線程dump、內存dump等信息創建快照)、其餘plugins的無限可能。
- 使用jvisualvm首次啓動時須要在線自動安裝插件(也可手工安裝);
- 特點功能:生成瀏覽堆轉儲快照(摘要、類、實例標籤頁、OQL控制檯)、分析程序性能(Profiler頁籤能夠錄製一段時間程序每一個方法執行次數和耗時)、BTrace動態日誌跟蹤(不中止目標程序運行的前提下經過HotSwap技術動態加入調試代碼);
第7章 虛擬機類加載機制
概述
- 虛擬機把描述類的數據從Class文件加載到內存,並對數據進行校驗、轉換解析和初始化,最終造成能夠被虛擬機直接使用的Java類型,這就是虛擬機的類加載機制。
- 在Java語言裏面,類型的加載、鏈接和初始化過程都是在程序運行期間完成,這雖然增量一些性能開銷,可是會爲Java應用程序提供高度的靈活性。
類加載的時機
- 類的整個生命週期:加載、驗證、準備、解析、初始化、使用和卸載;其中驗證、準備和解析統稱爲鏈接;
- 虛擬機規範沒有強制約束類加載的時機,但嚴格規定了有且只有5種狀況必須當即對類進行初始化:遇到new、getstatic、putstatic和invokestatic指令;對類進行反射調用時若是類沒有進行過初始化;初始化時發現父類尚未進行初始化;虛擬機啓動指定的主類;動態語言中MethodHandle實例最後解析結果REF_getStatic等的方法句柄對應的類沒有初始化時;
類加載的過程
1.加載
- 經過一個類的全限定名來獲取定義此類的二進制字節流;
- 將這個字節流所表明的靜態存儲結構轉化爲方法區的運行時數據結構;
- 在內存中生成一個表明這個類的java.lang.Class對象,做爲方法區這個類的各類數據的訪問入口;
2.驗證
- 驗證是鏈接階段的第一步,其目的是確保Class文件的字節流中包含的信息符合當前虛擬機的要求,而且不會危害虛擬機自身的安全;
- 驗證階段是很是重要的,這個階段是否嚴謹決定了Java虛擬機是否能承受惡意代碼的攻擊;
- 校驗動做:文件格式驗證(基於二進制字節流)、元數據驗證(對類的元數據語義分析)、字節碼驗證(對方法體語義分析)、符號引用驗證(對類自身之外的信息進行匹配性校驗);
3.準備
- 正式爲變量分配內存並設置類變量初始值的階段,這些變量所使用的內存都將在這個方法區中進行分配;
- 須要強調兩點:這時候內存分配的僅包括類變量,而不包括類實例變量;這裏所說的初始化一般狀況下是數據類型的零值,真正的賦值是在初始化階段,若是是static final的則是直接賦值;
4.解析
- 解析階段是虛擬機將常量池內的符號引用(如
CONSTANT_Class_info
、CONSTANT_Fieldref_info
、CONSTANT_Methodref_info
等7種)替換爲直接引用的過程;
- 符號引用能夠是任何形式的字面量,與虛擬機實現的內存佈局無關,引用的目標並不必定已經加載到內存中;而直接引用是直接指向目標的指針、相對偏移量或是一個能間接定位到目標的句柄,它和虛擬機實現的內存佈局相關,引用的目標一定以及在內存中存在;
- 對同一個符號引用進行屢次解析請求是很常見的事情,虛擬機實現能夠對第一次解析的結果進行緩存;
5.初始化
- 是類加載過程的最後一步,真正開始執行類中定義的Java程序代碼(或者說是字節碼);
- 初始化階段是執行類構造器方法的過程,該方法是由編譯器自動收集類中的全部類變量的賦值動做和靜態語句塊中的語句合併產生的;
- 方法與類的構造函數(或者說是實例構造器方法)不一樣,它不須要顯式地調用父類構造器,虛擬機會保證在子類的方法執行以前,父類的方法已執行完畢;
- 執行接口的方法不須要先執行父接口的方法,只有當父接口中定義的變量使用時父接口才會初始化,接口的實現類在初始化時也同樣不會執行接口的方法;
- 方法初始化是加鎖阻塞等待的,應當避免在方法中有耗時很長的操做;
類加載器
- 虛擬機設計團隊把類加載階段的「經過一個類的全限定名來獲取描述此類的二進制字節流」這個動做放到虛擬機外部去實現,實現這個動做的代碼模塊稱爲類加載器;
- 這是Java語言的一項創新,也是Java語言流行的重要緣由,在類層次劃分、OSGI、熱部署、代碼加密等領域大放異彩
類與類加載器
- 對於任意一個類,都須要由加載它的類加載器和這個類自己一同確立其在Java虛擬機的惟一性,每個類加載器都擁有一個獨立的類名稱空間;
- 比較兩個類是否相等(如Class對象的equals方法、isAssignableFrom方法、isInstance方法),只有在這兩個類是由同一個類加載器加載的前提下才有意義;
雙親委派模型
關於雙親委派模型,這篇文章寫得簡單易懂:http://www.jianshu.com/p/acc7595f1b9d
- 三種系統提供的類加載器:啓動類加載器(Bootstrap ClassLoader)、擴展類加載器(Extension ClassLoader)、應用程序類加載器(Application ClassLoader);
- 雙親委派模型要求除了頂層的啓動類加載器外,其餘的類加載器都應當有本身的父類加載器,這裏通常不會以繼承的關係來實現,而是使用組合的關係來複用父加載器的代碼;
- 其工做過程是:若是一個類加載器收到了類加載的請求,它首先不會本身去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,只有父類加載器反饋本身沒法完成這個加載請求時(它的搜索範圍中沒有找到所需的類),子加載器纔會嘗試本身去加載;
- 這樣的好處是Java類隨着它的類加載器具有了一種帶有優先級的層次關係,對保證Java程序的穩定運做很重要;
- 實現雙親委派的代碼都集中在java.lang.ClassLoader的loadClass方法中,邏輯清晰易懂;
JVM經常使用參數調節
內存參數
參數 |
做用 |
-Xmx |
堆大小的最大值。當前主流虛擬機的堆都是可擴展的 |
-Xms |
堆大小的最小值。能夠設置成和 -Xmx 同樣的值 |
-Xmn |
新生代的大小。現代虛擬機都是「分代」的,所以堆空間由新生代和老年代組成。新生代增大,相應地老年代就減少。Sun官方推薦新生代佔整個堆的3/8 |
-Xss |
每一個線程的堆棧大小。該值影響一臺機器可以建立的線程數上限 |
-XX:MaxPermSize= |
永久代的最大值。永久代是 HotSpot 特有的,HotSpot 用永久代來實現方法區 |
-XX:PermSize= |
永久代的最小值。能夠設置成和 -XX:MaxPermSize 同樣的值 |
-XX:SurvivorRatio= |
Eden 和 Survivor 的比值。基於「複製」的垃圾收集器又會把新生代分爲一個 Eden 和兩個 Survivor,若是該參數爲8,就表示 Eden |
-XX:PretenureSizeThreshold= |
直接晉升到老年代的對象大小。大於這個參數的對象將直接在老年代分配。默認值爲0,表示不啓用 |
-XX:HandlePromotionFailure= |
是否容許分配擔保失敗。在 JDK 6 Update 24 後該參數已經失效。 |
-XX:MaxTenuringThreshold= |
對象晉升到老年代的年齡。對象每通過一次 Minor GC 後年齡就加1,超過這個值時就進入老年代。默認值爲15 |
-XX:MaxDirectMemorySize= |
直接內存的最大值。對於頻繁使用 nio 的應用,應該顯式設置該參數,默認值爲0 |
GC參數
垃圾收集器 |
參數 |
備註 |
Serial(新生代) |
-XX:+UseSerialGC |
虛擬機在 Client 模式下的默認值,打開此開關後,使用 Serial + Serial Old 的收集器組合。Serial 是一個單線程的收集器 |
ParNew(新生代) |
-XX:+UseParNewGC |
強制使用 ParNew,打開此開關後,使用 ParNew + Serial Old 的收集器組合。ParNew 是一個多線程的收集器,也是 server 模式下首選的新生代收集器 |
|
-XX:ParallelGCThreads= |
垃圾收集的線程數 |
Parallel Scavenge(新生代) |
-XX:+UseParallelGC |
虛擬機在 Server 模式下的默認值,打開此開關後,使用 Parallel Scavenge + Serial Old 的收集器組合 |
|
-XX:MaxGCPauseMillis= |
單位毫秒,收集器儘量保證單次內存回收停頓的時間不超過這個值。 |
|
-XX:GCTimeRatio= |
總的用於 gc 的時間佔應用程序的百分比,該參數用於控制程序的吞吐量 |
|
-XX:+UseAdaptiveSizePolicy |
設置了這個參數後,就再也不須要指定新生代的大小(-Xmn)、 Eden 和 Survisor 的比例(-XX:SurvivorRatio)以及晉升老年代對象的年齡(-XX:PretenureSizeThreshold)了,由於該收集器會根據當前系統的運行狀況自動調整。固然前提是先設置好前兩個參數。 |
Serial Old(老年代) |
無 |
Serial Old 是 Serial 的老年代版本,主要用於 Client 模式下的老生代收集,同時也是 CMS 在發生 Concurrent Mode Failure 時的後備方案 |
Parallel Old(老年代) |
-XX:+UseParallelOldGC |
打開此開關後,使用 Parallel Scavenge + Parallel Old 的收集器組合。Parallel Old 是 Parallel Scavenge 的老年代版本,在注重吞吐量和 CPU 資源敏感的場合,能夠優先考慮這個組合 |
CMS(老年代) |
-XX:+UseConcMarkSweepGC |
打開此開關後,使用 ParNew + CMS 的收集器組合。 |
|
-XX:CMSInitiatingOccupancyFraction= |
CMS 收集器在老年代空間被使用多少後觸發垃圾收集 |
|
-XX:+UseCMSCompactAtFullCollection |
在完成垃圾收集後是否要進行一次內存碎片整理 |
|
-XX:CMSFullGCsBeforeCompaction= |
在進行若干次垃圾收集後才進行一次內存碎片整理 |
附圖:能夠配合使用的收集器組合
其餘參數
參數 |
做用 |
-verbose:class |
打印類加載過程 |
-XX:+PrintGCDetails |
發生垃圾收集時打印 gc 日誌,該參數會自動帶上 -verbose:gc 和 -XX:+PrintGC |
-XX:+PrintGCDateStamps / -XX:+PrintGCTimeStamps |
打印 gc 的觸發事件,能夠和 -XX:+PrintGC 和 -XX:+PrintGCDetails 混用 |
-Xloggc:<path> |
gc 日誌路徑 |
-XX:+HeapDumpOnOutOfMemoryError |
出現 OOM 時 dump 出內存快照用於過後分析 |
-XX:HeapDumpPath= |
堆轉儲快照的文件路徑 |
參考文章
1.Gino Zhang的博客總結的很全面 http://ginobefunny.com
2.關於雙親委派模型,這篇文章寫得簡單易懂:http://www.jianshu.com/p/acc7595f1b9d