內容簡介
不管技術如何發展,Java依然是一個充滿活力的生態圈,學習Java的人也越來越多,但多數人學習Java虛擬機(JVM)時都會遇到瓶頸。本書將通過200餘個示例詳細介紹JVM中的各種參數配置、故障排查、性能監控及性能最佳化,幫助Java人突破瓶頸。本書共11章,修訂後版本涵蓋Java 6~Java 10。第1~3章介紹了Java虛擬機的定義、總體架構、常用配置參數。第4~5章介紹了垃圾回收的算法和各種垃圾回收器。第6章介紹了Java虛擬機的性能監控和故障診斷工具。第7章詳細介紹了對Java堆的分析方法和案例。第8章介紹了Java虛擬機對多執行緒,尤其是對鎖的支持。第9~10章介紹了Java虛擬機的核心—Class檔案結構,以及Java虛擬機中類的裝載系統。第11章介紹了Java虛擬機的執行系統和位元組碼,並給出了通過ASM框架進行位元組碼注入的案例。本書不僅適合Java程式設計師閱讀,還適合工作於Java虛擬機之上的研發人員、軟體設計師、架構師閱讀。
圖書目錄
目 錄
第1章 初探Java虛擬機1
1.1 知根知底:追溯Java的發展歷程2
1.1.1 那些依託Java虛擬機的語言大咖們2
1.1.2 Java發展史上的里程碑2
1.2 跨平台的真相:Java虛擬機做中介4
1.2.1 理解Java虛擬機的原理4
1.2.2 看清Java虛擬機的種類5
1.3 一切看我的:Java語言規範6
1.3.1 詞法的定義6
1.3.2 語法的定義7
1.3.3 數據類型的定義8
1.3.4 Java語言規範總結9
1.4 一切聽我的:Java虛擬機規範9
1.5 數字編碼就是計算機世界的水和電10
1.5.1 整數在Java虛擬機中的表示10
1.5.2 浮點數在Java虛擬機中的表示12
1.6 拋磚引玉:編譯和調試虛擬機14
1.7 小結18
第2章 認識Java虛擬機的基本結構19
2.1 謀全局者才能成大器:看穿Java虛擬機的架構19
2.2 小參數能解決大問題:學會設定Java虛擬機的參數21
2.3 對象去哪兒:辨清Java堆22
2.4 函式如何調用:出入Java棧24
2.4.1 局部變數表26
2.4.2 運算元棧31
2.4.3 幀數據區31
2.4.4 棧上分配32
2.5 類去哪兒了:識別方法區34
2.6 小結36
第3章 常用Java虛擬機參數37
3.1 一切運行都有跡可循:掌握跟蹤調試參數37
3.1.1 跟蹤垃圾回收—讀懂虛擬機日誌38
3.1.2 類載入/卸載的跟蹤42
3.1.3 查看系統參數45
3.2 讓性能飛起來:學習堆的配置參數45
3.2.1 最大堆和初始堆的設定46
3.2.2 新生代的配置49
3.2.3 堆溢出處理53
3.3 別讓性能有缺口:了解非堆記憶體的參數配置54
3.3.1 方法區配置55
3.3.2 棧配置55
3.3.3 直接記憶體配置55
3.4 Client和Server二選一:虛擬機的工作模式58
3.5 小結59
第4章 垃圾回收的概念與算法60
4.1 記憶體管理清潔工:認識垃圾回收60
4.2 清潔工具大PK:討論常用的垃圾回收算法61
4.2.1 引用計數法(Reference Counting)62
4.2.2 標記清除法(Mark-Sweep)63
4.2.3 複製算法(Copying)64
4.2.4 標記壓縮法(Mark-Compact)66
4.2.5 分代算法(Generational Collecting)67
4.2.6 分區算法(Region)68
4.3 誰才是真正的垃圾:判斷可觸及性69
4.3.1 對象的復活69
4.3.2 引用和可觸及性的強度71
4.3.3 軟引用—可被回收的引用72
4.3.4 弱引用—發現即回收76
4.3.5 虛引用—對象回收跟蹤77
4.4 垃圾回收時的停頓現象:Stop-The-World案例實戰79
4.5 小結83
第5章 垃圾收集器和記憶體分配84
5.1 一心一意一件事:串列回收器85
5.1.1 新生代串列回收器85
5.1.2 老年代串列回收器86
5.2 人多力量大:並行回收器86
5.2.1 新生代ParNew回收器87
5.2.2 新生代ParallelGC回收器88
5.2.3 老年代ParallelOldGC回收器89
5.3 一心多用都不落下:CMS回收器(JDK 8及之前的版本)90
5.3.1 CMS主要工作步驟90
5.3.2 CMS主要的參數91
5.3.3 CMS的日誌分析93
5.3.4 有關Class的回收94
5.4 未來我做主:G1回收器(JDK 9及之後版本的默認回收器)95
5.4.1 G1的記憶體劃分和主要收集過程95
5.4.2 G1的新生代GC96
5.4.3 G1的並發標記周期97
5.4.4 混合回收100
5.4.5 必要時的Full GC102
5.4.6 G1的日誌102
5.4.7 G1相關的參數106
5.5 回眸:有關對象記憶體分配和回收的一些細節問題106
5.5.1 禁用System.gc()107
5.5.2 System.gc()使用並發回收107
5.5.3 並行GC前額外觸發的新生代GC109
5.5.4 對象何時進入老年代109
5.5.5 在TLAB上分配對象117
5.5.6 finalize()函式對垃圾回收的影響120
5.6 溫故又知新:常用的GC參數125
5.7 動手才是真英雄:垃圾回收器對Tomcat性能影響的實驗127
5.7.1 配置實驗環境127
5.7.2 配置性能測試工具JMeter128
5.7.3 配置Web套用伺服器Tomcat131
5.7.4 實戰案例1—初試串列回收器133
5.7.5 實戰案例2—擴大堆以提升系統性能133
5.7.6 實戰案例3—調整初始堆大小134
5.7.7 實戰案例4—使用ParrellOldGC回收器135
5.7.8 實戰案例5—使用較小堆提高GC壓力135
5.7.9 實戰案例6—測試ParallelOldGC的表現135
5.7.10 實戰案例7—測試ParNew回收器的表現136
5.7.11 實戰案例8—測試JDK 1.8的表現136
5.7.12 實戰案例9—使用高版本虛擬機提升性能137
5.8 小結137
第6章 性能監控工具138
6.1 有我更高效:Linux下的性能監控工具139
6.1.1 顯示系統整體資源使用情況—top命令139
6.1.2 監控記憶體和CPU—vmstat命令140
6.1.3 監控I/O—iostat命令142
6.1.4 多功能診斷器—pidstat工具143
6.2 用我更高效:Windows下的性能監控工具148
6.2.1 任務管理器148
6.2.2 perfmon性能監控工具150
6.2.3 Process Explorer進程管理工具153
6.2.4 pslist命令—Windows下也有命令行工具155
6.3 外科手術刀:JDK性能監控工具157
6.3.1 查看Java進程—jps命令158
6.3.2 查看虛擬機運行時信息—jstat命令159
6.3.3 查看虛擬機參數—jinfo命令162
6.3.4 導出堆到檔案—jmap命令163
6.3.5 JDK自帶的堆分析工具—jhat命令165
6.3.6 查看執行緒堆疊—jstack命令168
6.3.7 遠程主機信息收集—jstatd命令171
6.3.8 多功能命令行—jcmd命令173
6.3.9 性能統計工具—hprof175
6.3.10 擴展jps命令178
6.4 我是你的眼:圖形化虛擬機監控工具JConsole178
6.4.1 JConsole連線Java程式179
6.4.2 Java程式概況180
6.4.3 記憶體監控180
6.4.4 執行緒監控181
6.4.5 類載入情況183
6.4.6 虛擬機信息183
6.5 一目了然:可視化性能監控工具Visual VM184
6.5.1 Visual VM連線應用程式185
6.5.2 監控應用程式概況186
6.5.3 Thread Dump和分析187
6.5.4 性能分析188
6.5.5 記憶體快照分析190
6.5.6 BTrace介紹191
6.6 來自JRockit的禮物:虛擬機診斷工具Mission Control199
6.6.1 MBean伺服器199
6.6.2 飛行記錄器(Flight Recorder)201
6.7 小結204
第7章 分析Java堆205
7.1 對症才能下藥:找到記憶體溢出的原因206
7.1.1 堆溢出206
7.1.2 直接記憶體溢出206
7.1.3 過多執行緒導致OOM208
7.1.4 永久區溢出210
7.1.5 GC效率低下引起的OOM211
7.2 無處不在的字元串:String在虛擬機中的實現211
7.2.1 String對象的特點211
7.2.2 有關String的記憶體泄漏213
7.2.3 有關String常量池的位置216
7.3 虛擬機也有內窺鏡:使用MAT分析Java堆218
7.3.1 初識MAT218
7.3.2 淺堆和深堆221
7.3.3 MAT堆分析案例解析222
7.3.4 支配樹(Dominator Tree)226
7.3.5 Tomcat堆溢出分析227
7.4 篩選堆對象:MAT對OQL的支持231
7.4.1 Select子句231
7.4.2 From子句233
7.4.3 Where子句235
7.4.4 內置對象與方法235
7.5 更精彩的查找:Visual VM對OQL的支持240
7.5.1 Visual VM的OQL基本語法240
7.5.2 內置heap對象241
7.5.3 對象函式243
7.5.4 集合/統計函式247
7.5.5 程式化OQL分析Tomcat堆253
7.6 小結256
第8章 鎖與並發257
8.1 安全就是鎖存在的理由:鎖的基本概念和實現258
8.1.1 理解執行緒安全258
8.1.2 對象頭和鎖260
8.2 避免殘酷的競爭:鎖在Java虛擬機中的實現和最佳化261
8.2.1 偏向鎖261
8.2.2 輕量級鎖263
8.2.3 鎖膨脹264
8.2.4 自旋鎖265
8.2.5 鎖消除265
8.3 應對殘酷的競爭:鎖在套用層的最佳化思路267
8.3.1 減少鎖持有時間267
8.3.2 減小鎖粒度268
8.3.3 鎖分離270
8.3.4 鎖粗化272
8.4 無招勝有招:無鎖274
8.4.1 理解CAS274
8.4.2 原子操作275
8.4.3 新寵兒LongAdder278
8.5 將隨機變為可控:理解Java記憶體模型281
8.5.1 原子性281
8.5.2 有序性283
8.5.3 可見性285
8.5.4 Happens-Before原則287
8.6 小結287
第9章 Class檔案結構288
9.1 不僅跨平台,還能跨語言:語言無關性288
9.2 虛擬機的基石:Class檔案290
9.2.1 Class檔案的標誌—魔數291
9.2.2 Class檔案的版本293
9.2.3 存放所有常數—常量池294
9.2.4 Class的訪問標記(Access Flag)301
9.2.5 當前類、父類和接口302
9.2.6 Class檔案的欄位303
9.2.7 Class檔案的方法基本結構305
9.2.8 方法的執行主體—Code屬性307
9.2.9 記錄行號—LineNumberTable屬性308
9.2.10 保存局部變數和參數—LocalVariableTable屬性309
9.2.11 加快位元組碼校驗—StackMapTable屬性309
9.2.12 Code屬性總結314
9.2.13 拋出異常—Exceptions屬性315
9.2.14 用實例分析Class的方法結構316
9.2.15 我來自哪裡—SourceFile屬性319
9.2.16 強大的動態調用—BootstrapMethods屬性320
9.2.17 內部類—InnerClasses屬性321
9.2.18 將要廢棄的通知—Deprecated屬性322
9.2.19 Class檔案總結323
9.3 操作位元組碼:走進ASM323
9.3.1 ASM體系結構323
9.3.2 ASM之Hello World325
9.4 小結326
第10章 Class裝載系統327
10.1 來去都有序:看懂Class檔案的裝載流程327
10.1.1 類裝載的條件328
10.1.2 載入類331
10.1.3 驗證類333
10.1.4 準備334
10.1.5 解析類335
10.1.6 初始化337
10.2 一切Class從這裡開始:掌握ClassLoader341
10.2.1 認識ClassLoader,看懂類載入342
10.2.2 ClassLoader的分類342
10.2.3 ClassLoader的雙親委託模式344
10.2.4 雙親委託模式的弊端348
10.2.5 雙親委託模式的補充349
10.2.6 突破雙親模式351
10.2.7 熱替換的實現354
10.3 小結358
第11章 位元組碼執行359
11.1 代碼如何執行:位元組碼執行案例360
11.2 執行的基礎:Java虛擬機常用指令介紹370
11.2.1 常量入棧指令370
11.2.2 局部變數壓棧指令370
11.2.3 出棧裝入局部變數表指令372
11.2.4 通用型操作373
11.2.5 類型轉換指令374
11.2.6 運算指令376
11.2.7 對象操作指令378
11.2.8 比較控制指令380
11.2.9 函式調用與返回指令386
11.2.10 同步控制389
11.2.11 再看Class的方法結構392
11.3 更上一層樓:再看ASM393
11.3.1 為類增加安全控制394
11.3.2 統計函式執行時間397
11.4 誰說Java太刻板:Java Agent運行時修改類400
11.4.1 使用-javaagent參數啟動Java虛擬機400
11.4.2 使用Java Agent為函式增加計時功能403
11.4.3 動態重轉換類404
11.4.4 有關Java Agent的總結407
11.5 與時俱進:動態方法調用407
11.5.1 方法句柄使用實例408
11.5.2 調用點使用實例411
11.5.3 反射和方法句柄413
11.5.4 指令invokedynamic使用實例414
11.6 跑得再快點:靜態編譯最佳化419
11.6.1 編譯時計算419
11.6.2 變數字元串的連線421
11.6.3 基於常量的條件語句裁剪422
11.6.4 switch語句的最佳化424
11.7 提高虛擬機的執行效率:JIT及其相關參數425
11.7.1 開啟JIT編譯425
11.7.2 JIT編譯閾值426
11.7.3 多級編譯器427
11.7.4 OSR棧上替換430
11.7.5 方法內聯432
11.7.6 設定代碼快取大小433
11.8 小結436