采用Java開(kāi)發(fā)的大型應(yīng)用系統(tǒng)越來(lái)越大、越來(lái)越復(fù)雜;很多系統(tǒng)甚至是將很多第三方系統(tǒng)集成在一起,整個(gè)系統(tǒng)看起來(lái)像一個(gè)黑盒子。系統(tǒng)運(yùn)行遭遇問(wèn)題(系統(tǒng)停止響應(yīng),運(yùn)行越來(lái)越慢,或者性能低下,甚至系統(tǒng)core dump),如何迅速命中問(wèn)題的根本原因是頗具挑戰(zhàn)性的任務(wù)。 特別的是,有些非功能性的問(wèn)題只能在生產(chǎn)環(huán)境上重現(xiàn),而生產(chǎn)環(huán)境不允許停機(jī)維護(hù),這給問(wèn)題的定位帶來(lái)巨大的困難。這類問(wèn)題的定位技巧是本書介紹的重點(diǎn),借助這些技巧可以快速 找到這些問(wèn)題的突破口。
本書共有15章,包括Java線程堆棧分析、性能瓶頸分析、內(nèi)存泄露分析、并發(fā)和多線程、幽靈代碼、常見(jiàn)Java泥潭、JVM、字符集與編碼、常用問(wèn)題定位工具、Java實(shí)踐等內(nèi)容。本書適合Java高級(jí)程序員和系統(tǒng)構(gòu)架師閱讀。
張民衛(wèi),深圳市哈蜜淘科技有限公司·首席技術(shù)執(zhí)行官CTO,曾在華為任職11年(2000~2011),歷任軟件工程師、系統(tǒng)架構(gòu)師,技術(shù)支持代表。作為華為技術(shù)支持體系最高一級(jí)(研發(fā)支持),主持華為公司所有基于 Java 語(yǔ)言平臺(tái)的產(chǎn)品的疑難問(wèn)題技術(shù)攻關(guān)工作。所支持產(chǎn)品覆蓋全球130 多個(gè)國(guó)家,絕大多時(shí)間處理網(wǎng)上事故以及根因分析。在高可靠性(電信領(lǐng)域要求達(dá)到99.999%可用性)領(lǐng)域有很深的造詣。
第 1 章 Java 線程堆棧分析 1
1.1 打印線程堆棧 3
1.2 解讀線程堆棧 4
1.3 線程堆棧分析的三個(gè)視角24
1.3 借助線程堆棧進(jìn)行問(wèn)題分析26
第 2 章 通過(guò) Java 線程堆棧進(jìn)行性能瓶頸分析 43
2.1 基本原理分析44
2.2 常見(jiàn)的性能瓶頸問(wèn)題50
2.3 性能瓶頸分析的手段和工具51
2.4 性能分析的手段總結(jié)59
第 3 章 Java 內(nèi)存泄漏分析和堆內(nèi)存設(shè)置 62
3.1 Java 內(nèi)存泄漏的背景知識(shí)63
3.2 Java 內(nèi)存泄漏的癥狀81
3.3 Java 內(nèi)存泄漏的定位和分析83
3.4 Java 堆內(nèi)存泄漏的解決92
3.5 Java 內(nèi)存和垃圾的回收設(shè)置94
第 4 章 關(guān)于并發(fā)和多線程102
4.1 在什么情況下需要加鎖103
4.2 如何加鎖104
4.3 多線程編程易犯的錯(cuò)誤106
4.4 i++ 這種原子操作是否需要同步保護(hù)107
4.5 一個(gè)進(jìn)程擁有的線程多,是否就可以獲得更多的 CPU 107
4.6 合理設(shè)置線程的數(shù)量107
4.7 關(guān)于線程池109
4.8 notify 和 wait 的組合 109
4.9 線程的阻塞 113
4.10 Java 線程的優(yōu)先級(jí) 115
4.11 關(guān)于多線程的錯(cuò)誤觀點(diǎn) 115
第 5 章 幽靈代碼116
5.1 由異常而導(dǎo)致的函數(shù)非自主退出 117
5.2 wait () 與循環(huán)123
5.3 Double-Checked Locking 單例模式124
5.4 另一種異常陷阱——連續(xù)的關(guān)鍵接口調(diào)用 125
第 6 章 常見(jiàn)的 Java 陷阱 127
6.1 不穩(wěn)定的 Runtime、getRuntime()、exec ()128
6.2 JDK 自帶 Timer 的適用場(chǎng)合140
6.3 JDK 自帶線程池的陷阱146
6.4 Timer 的使用陷阱146
第 7 章 關(guān)于數(shù)據(jù)庫(kù)147
7.1 關(guān)于數(shù)據(jù)庫(kù)表死鎖與鎖表的問(wèn)題148
7.2 Oracle 的鎖表 / 死鎖151
7.3 使用事務(wù)的方法153
第 8 章 字符集與編碼 154
8.1 字符集155
8.2 編碼155
8.3 編碼的識(shí)別157
8.4 關(guān)于編碼的轉(zhuǎn)換158
第 9 章 JVM 運(yùn)行參數(shù)解析 160
9.1 Java 運(yùn)行期參數(shù)161
9.2 Java -X 擴(kuò)展運(yùn)行參數(shù)167
9.3 關(guān)于即時(shí)編譯器(JIT)171
9.4 -Xrunhprof172
9.5 正確的視角看虛擬機(jī)180
第 10 章 常用的問(wèn)題定位工具181
10.1 遠(yuǎn)程調(diào)試 182
10.2 UNIX 下的進(jìn)行分析利器 proc 182
10.3 UNIX 的進(jìn)程統(tǒng)計(jì)工具 prstat187
10.4 UNIX 的剖析工具 188
10.5 路由跟蹤命令 traceroute/tracert 188
10.6 swap 交換分區(qū)管理189
10.7 文件類型 / 符號(hào)表 189
10.8 Windows 的相關(guān)工具 189
第 11 章 計(jì)算架構(gòu)與存儲(chǔ)架構(gòu)191
11.1 計(jì)算架構(gòu)——基于無(wú)狀態(tài)的設(shè)計(jì)192
11.2 存儲(chǔ)架構(gòu)——數(shù)據(jù)分片196
11.3 存儲(chǔ)架構(gòu)的總結(jié)199
11.4 其他架構(gòu)的設(shè)計(jì)建議200
第 12 章 項(xiàng)目生命周期與框架、語(yǔ)言、開(kāi)源選擇202
12.1 以項(xiàng)目時(shí)間尺度衡量開(kāi)發(fā)語(yǔ)言的選擇 203
12.2 以項(xiàng)目時(shí)間尺度衡量開(kāi)發(fā)框架的使用策略 204
12.3 以項(xiàng)目時(shí)間尺度衡量開(kāi)源的選擇 205
第 13 章 設(shè)計(jì)“工業(yè)強(qiáng)度”的軟件系統(tǒng)207
13.1 長(zhǎng)期運(yùn)行能力的構(gòu)建 208
13.2 瞬時(shí)峰值 / 過(guò)載的應(yīng)對(duì)能力構(gòu)建 208
13.3 池的合理設(shè)計(jì) 210
13.4 消息系統(tǒng)的設(shè)計(jì)模型和關(guān)鍵點(diǎn) 215
第 14 章 工程實(shí)踐221
14.1 關(guān)于高端機(jī)器的系統(tǒng)部署 222
14.2 關(guān)于物理機(jī)與虛擬化 222
14.3 關(guān)于 Java 進(jìn)程監(jiān)控223
14.4 關(guān)于 class Loader223
14.5 關(guān)于負(fù)載控制 224
14.6 關(guān)于機(jī)器設(shè)置多個(gè) IP 的原理 225
14.7 關(guān)于日志 225
14.8 異常處理的原則 228
14.9 基于限制的系統(tǒng)部署 / 設(shè)計(jì) 228
14.10 String 的值不能改變的原因229
14.11 系統(tǒng)出現(xiàn)問(wèn)題時(shí)需要收集的信息 229
14.12 Web Failover 集群的方案 229
14.13 關(guān)于可靠性設(shè)計(jì)232
14.14 實(shí)現(xiàn) JVM Shutdown 鉤子函數(shù)232
14.15 截取輸出流233
14.16 將 Linux 進(jìn)程綁定在特定的 CPU 上運(yùn)行234
14.17 關(guān)于 Java 和 C++ 的互通 234
第 15 章 常見(jiàn)的案例236
15.1 太多打開(kāi)的文件 237
15.2 java.lang.StackOverflflowError 239
15.3 java.net.SocketException: Broken pipe 240
15.4 HashMap 的 ConcurrentModiftcationException 241
15.5 多線程場(chǎng)合下 HashMap 導(dǎo)致的無(wú)限死循環(huán) 242
15.6 Web 系統(tǒng)吊死(掛死)的定位思路 245
15.7 基于消息系統(tǒng)(如 SIP)吊死的定位思路 247
15.8 多線程讀 / 寫 Socket 導(dǎo)致的數(shù)據(jù)混亂 247
15.9 CPU 使用率過(guò)高問(wèn)題的定位思路248
15.10 系統(tǒng)運(yùn)行越來(lái)越慢的定位思路251
15.11 系統(tǒng)掛死問(wèn)題的定位思路 252
15.12 關(guān)于線程死亡 / 線程跑飛253
15.13 關(guān)于虛擬機(jī) core dump255
15.14 系統(tǒng)運(yùn)行越來(lái)越慢問(wèn)題的定位思路257
15.15 代碼 GC 導(dǎo)致的性能低下 257
15.16 連接池耗盡259
15.17 更改系統(tǒng)時(shí)間導(dǎo)致的系統(tǒng)無(wú)法正常工作260
15.18 瞬間內(nèi)存泄漏的定位思路261
15.19 第三方系統(tǒng)能力分析262
15.20 系統(tǒng)性能過(guò)低264
15.21 未捕獲的異常導(dǎo)致數(shù)據(jù)庫(kù)鎖表,全系統(tǒng)連鎖宕機(jī)267
15.22 單機(jī)內(nèi)存泄漏導(dǎo)致數(shù)據(jù)庫(kù)鎖表,全系統(tǒng)連鎖宕機(jī)268
15.23 AIX 下 CPU 使用率被 100% 占用的定位思路270
15.24 Linux 下提高 UDP 吞吐量270
15.25 TIME_WAIT 狀態(tài)下連接不能及時(shí)釋放270
15.26 由 SAN 存儲(chǔ)鏈路問(wèn)題引起的應(yīng)用層白屏 272
附錄 A JProfiler 內(nèi)存泄漏的精確定位 275
附錄 B SUN JDK 自帶故障定位280
附 B.1 SUN JDK 命令行選項(xiàng)280
附 B.2 診斷工具的詳細(xì)介紹282
附 B.3 內(nèi)存泄漏問(wèn)題的定位317
附 B.4 系統(tǒng)崩潰的定位方法327
附 B.5 致命錯(cuò)誤日志335
附錄 C Solaris 下查找占用指定的端口的進(jìn)程351
附錄 D 如何在 solaris 下分析 I/O 瓶頸352
附錄 E AIX 下 32 位進(jìn)程的最大內(nèi)存占有情況353
附錄 F 關(guān)于 TCP/IP354
附錄 G Windows 2003/Windows XP 下一個(gè)端口多個(gè)監(jiān)聽(tīng)355
附錄 G 在 Windows 2003/Windows XP 下一個(gè)端口多個(gè)監(jiān)聽(tīng)356
附錄 H Suse 9.0 下線程創(chuàng)建的數(shù)量和堆內(nèi)存 / 永久內(nèi)存的關(guān)系357
附錄 I JConsole358
附錄 J Gcviewer 359
附錄 K IBM JDK 下定位引起 core dump 的 JIT 方法360
附錄 L 一份簡(jiǎn)短的 Java 編程規(guī)范 361
參考文獻(xiàn)363