前言
作為Java程式設計師,你有沒有被JVM傷害過?面試的時候是否碰到過對JVM的靈魂拷問?

一、JVM 記憶體區域劃分
1.程式計數器(執行緒私有)
程式計數器(Program Counter Register),也有稱作為 PC 暫存器。儲存的是程式當前執行的指令的地址(也可以說儲存下一條指令的所在儲存單元的地址),當 CPU 需要執行指令時,需要從程式計數器中得到當前需要執行的指令所在儲存單元的地址,然後根據得到的地址獲取到指令,在得到指令之後,程式計數器便自動加 1 或者根據轉移指標得到下一條指令的地址,如此迴圈,直至執行完所有的指令。也就是說是用來指示執行哪條指令的。
由於在 JVM 中,多執行緒是通過執行緒輪流切換來獲得 CPU 執行時間的,因此,在任一具體時刻,一個 CPU 的核心只會執行一條執行緒中的指令,因此,為了能夠使得每個執行緒都線上程切換後能夠恢復在切換之前的程式執行位置,每個執行緒都需要有自己獨立的程式計數器,並且不能互相被干擾,否則就會影響到程式的正常執行次序。因此,可以這麼說,程式計數器是每個執行緒所私有的。
在 JVM 規範中規定,如果執行緒執行的是非 native 方法,則程式計數器中儲存的是當前需要執行的指令的地址;如果執行緒執行的是 native 方法,則程式計數器中的值是 undefined。
由於程式計數器中儲存的資料所佔空間的大小不會隨程式的執行而發生改變,因此,對於程式計數器是不會發生記憶體溢位現象(OutOfMemory)的。
異常情況:
不存在
2.Java 棧(執行緒私有)
3.本地方法棧(執行緒私有)
4.堆(執行緒共享)
5.方法區(執行緒共享)
6.直接記憶體(執行緒共享)

二、JVM 執行子系統
1.Class 類檔案結構
1.1 Java 跨平臺的基礎
各種不同平臺的虛擬機器與所有平臺都統一使用的程式儲存格式——位元組碼(ByteCode)是構成平臺無關性的基石,也是語言無關性的基礎。Java 虛擬機器不和包括 Java 在內的任何語言繫結,它只與“Class 檔案”這種特定的二進位制檔案格式所關聯,Class 檔案中包含了 Java虛擬機器指令集和符號表以及若干其他輔助資訊。
1.2 Class 類的本質
任何一個 Class 檔案都對應著唯一一個類或介面的定義資訊,但反過來說,Class 檔案實際上它並不一定以磁碟檔案的形式存在。Class 檔案是一組以 8 位位元組為基礎單位的二進位制流。
1.3 Class 檔案格式
各個資料專案嚴格按照順序緊湊地排列在 Class 檔案之中,中間沒有新增任何分隔符,這使得整個 Class 檔案中儲存的內容幾乎全部是程式執行的必要資料,沒有空隙存在。Class 檔案格式採用一種類似於 C 語言結構體的偽結構來儲存資料,這種偽結構中只有兩種資料型別:無符號數和表。
無符號數屬於基本的資料型別,以 u1、u2、u4、u8 來分別代表 1 個位元組、2 個位元組、4 個位元組和 8 個位元組的無符號數,無符號數可以用來描述數字、索引引用、數量值或者按照 UTF-8編碼構成字串值。
表是由多個無符號數或者其他表作為資料項構成的複合資料型別,所有表都習慣性地以“_info”結尾。表用於描述有層次關係的複合結構的資料,整個 Class 檔案本質上就是一張表。
2.位元組碼指令
2.1 載入和儲存指令
2.2 運算或算術指令
2.3 型別轉換指令
2.4 建立類例項的指令
2.5 建立陣列的指令
2.6 訪問欄位指令
2.7 陣列存取相關指令
2.8 檢查類例項型別的指令
2.9 運算元棧管理指令
2.10 控制轉移指令
2.11 方法呼叫指令

2.12 方法返回指令
2.13 異常處理指令
2.14 同步指令
3.類載入機制
4.類載入器
4.1 系統的類載入器
4.2 雙親委派模型
5.Tomcat 類載入機制
6.方法呼叫詳解
6.1 解析
6.2 靜態分派
6.3 動態分派
6.4 基於棧的位元組碼解釋執行引擎

三.垃圾回收器和記憶體分配策略
1.Java 中是值傳遞還是引用傳遞?
2.引用型別
3.基本垃圾回收演算法
3.1.1 引用計數(Reference Counting):
比較古老的回收演算法。原理是此物件有一個引用,即增加一個計數,刪除一個引用則減少一個計數。垃圾回收時,只用收集計數為 0 的物件。此演算法最致命的是無法處理迴圈引用的問題。
3.1.2 可達性分析清理

標記-清除(Mark-Sweep):此演算法執行分兩階段。第一階段從引用根節點開始標記所有被引用的物件,第二階段遍歷整個堆,把未標記的物件清除。此演算法需要暫停整個應用,同時,會產生記憶體碎片。

複製(Copying): 此演算法把記憶體空間劃為兩個相等的區域,每次只使用其中一個區域。垃圾回收時,遍歷當前使用區域,把正在使用中的物件複製到另外一個區域中。次演算法每次只處理正在使用中的物件,因此複製成本比較小,同時複製過去以後還能進行相應的記憶體整理,不會出現“碎片”問題。當然,此演算法的缺點也是很明顯的,就是需要兩倍記憶體空間。

標記-整理(Mark-Compact):此演算法結合了“標記-清除”和“複製”兩個演算法的優點。也是分兩階段,第一階段從根節點開始標記所有被引用物件,第二階段遍歷整個堆,清除標記物件,並未標記物件並且把存活物件“壓縮”到堆的其中一塊,按順序排放。此演算法避免了“標記-清除”的碎片問題,同時也避免了“複製”演算法的空間問題。
3.1 按照基本回收策略分
3.2 按分割槽對待的方式分
3.3 按系統執行緒分
4.分代處理垃圾
5.JAVA 中垃圾回收 GC 的型別

四、編寫高效優雅 Java 程式
1.物件導向
1.1 構造器引數太多怎麼辦?
用 builder 模式,用在
(1)5 個或者 5 個以上的成員變數
(2)引數不多,但是在未來,引數會增加
Builder 模式:
屬於物件的建立模式,一般有
(1)抽象建造者:一般來說是個介面,包含
1)建造方法,建造部件的方法(不止一個)
2)返回產品的方法
(2) 具體建造者
(3) 導演者,呼叫具體的建造者,建立產品物件
(4)產品,需要建造的複雜物件
對於客戶端,建立導演者和具體建造者,並把具體建造者交給導演者,然後由客戶端通知導演者操縱建造者進行產品的建立。
在實際的應用過程中,有時會省略抽象建造者和導演者。
1.2 不需要例項化的類應該構造器私有
1.3 不要建立不必要的物件
1.4 避免使用終結方法
1.5 使類和成員的可訪問性最小化
1.6 使可變性最小化
1.7 複合優先於繼承
1.8 介面優於抽象類
2.方法
2.1 可變引數要謹慎使用
2.2 返回零長度的陣列或集合,不要返回 null
2.3 優先使用標準的異常
3.通用程式設計

五、效能優化
一個 web 應用不是一個孤立的個體,它是一個系統的部分,系統中的每一部分都會影響整
個系統的效能
1.常用的效能評價/測試指標
1.1 響應時間
提交請求和返回該請求的響應之間使用的時間,一般比較關注平均響應時間。
常用操作的響應時間列表:

1.2 併發數
同一時刻,對伺服器有實際互動的請求數。
和網站線上使用者數的關聯:1000 個同時線上使用者數,可以估計併發數在 5%到 15%之間,也就是同時併發數在 50~150 之間。
1.3 吞吐量
對單位時間內完成的工作量(請求)的量度
1.4 關係
系統吞吐量和系統併發數以及響應時間的關係:
理解為高速公路的通行狀況:
吞吐量是每天通過收費站的車輛數目(可以換算成收費站收取的高速費),併發數是高速公路上的正在行駛的車輛數目,響應時間是車速。車輛很少時,車速很快。但是收到的高速費也相應較少;
隨著高速公路上車輛數目的增多,車速略受影響,但是收到的高速費增加很快;
隨著車輛的繼續增加,車速變得越來越慢,高速公路越來越堵,收費不增反降;
如果車流量繼續增加,超過某個極限後,任務偶然因素都會導致高速全部癱瘓,車走不動,當然後也收不著,而高速公路成了停車場(資源耗盡)。
2.常用的效能優化手段
2.1 避免過早優化
2.2 進行系統效能測試
2.3 尋找系統瓶頸,分而治之,逐步優化
2.4 前端優化常用手段

3 應用服務效能優化
3.1 快取
3.1.1 快取的基本原理和本質
3.1.2 合理使用緩衝的準則
3.1.3 分散式快取與一致性雜湊
3.2 非同步
3.2.1 同步和非同步,阻塞和非阻塞
3.2.2 常見非同步的手段
3.3 叢集

3.4 應用相關
3.4.1 程式碼級別
3.4.2 併發程式設計
3.4.3 資源的複用
3.4.4 JVM
3.4.5 GC 調優
3.4.6 調優實戰
3.4.7 儲存效能優化
上面的這些問題只是給大家一個借鑑作用,最主要的是給自己增加知識的儲備,有備無患。
關於JVM與效能調優總結了將近50頁pdf文件,歡迎關注我的公種浩:程式設計師追風,獲取這些整理的資料!

希望能幫助到你面試前的複習且找到一個好的工作,也節省大家在網上搜尋資料的時間來學習。
最後
歡迎大家一起交流,喜歡文章記得關注我點個贊喲,感謝支援!