JVM知識點梳理
JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用于計算設備的規范,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實作的,Java虛擬機包括一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域, JVM屏蔽了與具體作業系統平臺相關的資訊,使Java程式只需生成在Java虛擬機上運行的目標代碼(位元組碼),就可以在多種平臺上不加修改地運行,JVM在執行位元組碼時,實際上最侄訓是把位元組碼解釋成具體平臺上的機器指令執行,
JVM 組成部分

如上面的架構圖所示,JVM分為三個主要子系統:
- Class Loader子系統
- 運行時資料區
- 執行引擎
ClassLoader子系統
Java的動態類加載功能由ClassLoader子系統處理,它加載,鏈接,并在運行時(而非編譯時)首次參考類似初始化類檔案,
加載
類將由此組件加載,BootStrap ClassLoader,擴展ClassLoader和Application ClassLoader是有助于實作該目標的三個ClassLoader,
- BootStrap ClassLoader :負責從引導類路徑中加載類,僅用于rt.jar,最高優先級將給予此加載程式,
- 擴展ClassLoader :負責加載ext檔案夾(jre \ lib)內的類,
- Application ClassLoader :負責加載應用程式級別的類路徑,提到的環境變數路徑等,
連結
- 驗證:位元組碼驗證程式將驗證生成的位元組碼是否正確,如果驗證失敗,我們將收到驗證錯誤,
- 準備:將為所有靜態變數分配記憶體并為其分配默認值,
- 解決:將所有符號記憶體參考替換為“方法區域”中的原始參考,
初始化
這是ClassLoading的最后階段;在此,所有靜態變數將被分配原始值,并且將執行靜態塊,
運行時資料區
運行時資料區分為五個主要部分:
1、方法區域 :所有類級別的資料(包括靜態變數)都將存盤在此處,每個JVM只有一個方法區域,它是共享資源,
2、堆區 :所有物件及其對應的實體變數和陣列將存盤在此處,每個JVM還有一個堆區,由于“方法”和“堆”區域共享多個執行緒的記憶體,因此存盤的資料不是執行緒安全的,
3、堆疊區 :對于每個執行緒,將創建一個單獨的運行時堆疊,對于每個方法呼叫,將在堆疊存盤器中創建一個條目,稱為堆疊幀,所有區域變數都將在堆疊存盤器中創建,堆疊區域不是共享資源,因此是執行緒安全的,堆疊框架分為三個子物體:
- 區域變數陣列——與該方法有關,涉及多少區域變數,并且相應的值將存盤在此處,
- 運算元堆疊——如果需要執行任何中間操作,則運算元堆疊充當執行該操作的運行時作業區,
- 幀資料——與該方法相對應的所有符號都存盤在此處,在任何例外情況下,捕獲塊資訊將保留在幀資料中,
4、PC暫存器 :每個執行緒將具有單獨的PC暫存器,以在執行指令后保存當前執行指令的地址,PC暫存器將用下一條指令進行更新,
5、本機方法堆疊 :本機方法堆疊保存本機方法資訊,對于每個執行緒,將創建一個單獨的本機方法堆疊,
執行引擎
分配給運行時資料區的位元組碼將由執行引擎執行,執行引擎讀取位元組碼并逐段執行,
1、解釋器:解釋器解釋位元組碼的速度較快,但執行速度較慢,解釋器的缺點是,當多次呼叫一種方法時,每次都需要新的解釋,
2、JIT編譯器:JIT編譯器消除了解釋器的缺點,執行引擎將使用解釋器的幫助來轉換位元組碼,但是當發現重復的代碼時,它將使用JIT編譯器,該編譯器將編譯整個位元組碼并將其更改為本地代碼,此本地代碼將直接用于重復的方法呼叫,從而提高系統的性能,
- 中間代碼生成器——產生中間代碼
- 代碼優化器——負責優化上面生成的中間代碼
- 目標代碼生成器——負責生成機器代碼或本機代碼
- Profiler——一個特殊的組件,負責查找熱點,即是否多次呼叫該方法,
3、垃圾收集器:收集并洗掉未參考的物件,垃圾回收可以通過呼叫觸發System.gc(),但不能保證執行,JVM的垃圾收集收集創建的物件,
相信看到這里,大家對多執行緒應該有了基本的認識,那接下來咱們一起來看相應的學習路線,
JVM學習路線

是不是感覺比較繁瑣?不用擔心,在這里小編早已經將清華大佬的學習秘籍幫大家整理好了,為了不影響大家的閱讀體驗,小編只是展示了一部分細節,有需要深度學習的朋友,請幫忙轉發+關注小編,在私信回復【學習】即可免費領取哦~~~
第1章:Java虛擬機概述
本章簡單介紹了Java語言產生的歷史背景,Java語言所要解決的是如何能夠不關注底層技術細節就能實作兼容性,詹爺給出的答案是使用中間語言,通過中間語言來實作跨平臺兼容的目標,
章節簡介
- 從機器語言到Java——詹爺, 你好
- 兼容的選擇:一場生產力的革命
- 中間語言翻譯
- 常見匯編指令
- JVM指令

第2章:Java執行引擎作業原理:方法呼叫
本章主要講解了JVM內部的call stub 例程的定義和呼叫機制,但是并沒有一開始便直入主題,主要是考慮到技術的難度太大,很多人理解不了,因此作者只能用心良苦地設計了很多C和匯編程式,從物理機器執行函式呼叫的機制開始講起,為大家揭開物理機器在呼叫函式時設計的若干細節,
章節簡介
- 方法呼叫
- 真實的機器呼叫
- C語言函式呼叫
- JVM的函式呼叫機制
- 函式指標
- CallStub函式指標定義
- _call_ stub_ _entry 例程

第3章:Java資料結構與面向物件
從程式的角度看,資料結構是若干資料的有機結合,一個陣列、一個鏈表、一個堆疊都是資料集,這些資料在記憶體位置上有著緊密的聯系,例如,對于陣列而言,相鄰的兩個元素在記憶體位置上也是彼此相鄰的;而對于鏈表,記憶體空間上未必彼此相連,但是相鄰的兩個元素中必定有一個元素保存著一個指標指向另一個元素的記憶體位置,而從人類的角度看,一個特定的資料結構可以更好地描述客觀世界,例如通過一個Java類可以描述一只貓、一個手機,而通過類的組合則可以描述幾乎任意復雜的事物,這便是資料結構的意義所在,
章節簡介
- 從Java演算法到資料結構
- 資料型別簡史
- Java資料結構之偶然性
- Java型別識別
- 大端和小端的概念
- 大小端產生的本質原因
- 大小端驗證
- 大端和小端產生的場景
- 如何解決位元組序反轉
- 大小端問題的避免
- JVM對位元組碼檔案的大小端處理

第4章:Java位元組碼實戰
本章以一個具體的Java程式為例,分析了其對應的位元組碼檔案中的資料,可以發現,Java編譯器在生成Javaclass位元組碼檔案時,全是按套路出牌的,那么我們在分析時也按照套路走,便不難理解位元組碼檔案的內容,
位元組碼檔案中最重要的是Java方法所對應的位元組碼指令( 至少筆者這么認為), Java 源程式的邏輯都封裝在位元組碼指令中,對位元組碼指令在位元組碼檔案中的存盤方式有了透徹的理解,便意味著你對JVM執行引擎入門了,
章節簡介
- 位元組碼格式初探
- 魔數與版本
- 常量池的基本結構
- JVM所定義的11種常量
- 常量池元素的復合結構
- 常量池的結束位置
- 訪問標識與繼承資訊
- 欄位資訊
- 方法資訊

第5章:常量池決議
本章詳細分析了決議Java位元組碼常量池的原理,描述了JVM內部常量池物件的記憶體分配機制,并由此闡述了JVM內部的物件表示機制——oop-klass 模型,想要研究JVM內核的道友應當認真閱讀本章,最好能夠非常熟悉常量池的記憶體分配機制,因為后續章節會講解Java欄位、方法的記憶體分配機制,而Java欄位和方法的記憶體分配機制基本與常量池的記憶體分配機制類似,因此對常量池的記憶體分配機制理解得越透徹,則后續理解其他物件的記憶體分配機制便會越輕松,
章節簡介
- 常量池記憶體分配總體鏈路.
- 記憶體分配
- 初始化記憶體
- oop-klass模型
- 常量池klass模型(1)
- 常量池klass模型(2)
- constantPoolOop域
- 初始化tag
- 決議常量池元素

第6章:類變數決議
總體而言,HotSpot 決議Java類變數的脈絡比較清晰,但是也可以看出花了很多心思,這導致JVM雖然在執行引擎上相比于那些直接編譯成本地機器碼的編程語言可能要稍遜一籌, 但是在物件的記憶體分配上,并不比這些編程語言多浪費一點空間(除了每個Java類物件必須保留一個物件頭),甚至由于欄位重排的優化策略,對記憶體的利用率還要高于這些編程語言的編譯器的分配演算法,
章節簡介
- 類變數決議
- 靜態變數偏移量
- 非靜態變數偏移量
- Java欄位記憶體分配總結
- 欄位重排與補白
- private欄位可被繼承嗎
- 使用HSDB驗證欄位分配與繼承
- 參考型別變數記憶體分配

第7章:Java堆疊幀
本章全面分析了Java方法堆疊幀創建的程序,機器指令幾乎是逐個講解的,然而,筆者在閱讀JVM的這部分機制指令的程序中,不僅僅停留于分析機器指令本身的含義,還進行了更深入的思考,仔細推敲了每一潭訓器指令的背景,為何要這么實作,如果不這么實作有沒有問題,相信真正有耐心讀下來并且能夠讀懂的道友能夠體會筆者的這種深人思考!
章節簡介
- entry_ point 例程生成
- constMethod的記憶體布局
- 區域變數表空間計算
- 初始化區域變數區
- 堆疊幀是什么
- 硬體對堆疊的支持
- 堆疊幀開辟與回收
- 堆疊大小與多執行緒
- JVM堆疊幀與大小確定
- 堆疊幀創建
- 區域變數表
- 堆疊幀深度與slot復用
- 最大運算元堆疊與操作堆疊復用

第8章:類方法決議
本章主要描述了Java方法決議的技術實作,相比于前面章節所講解的Java類欄位的決議,Java類方法決議明顯要復雜得多,這種復雜性體現在Java方法屬性本身擁有眾多資訊,尤其是位元組碼指令部分,除了位元組碼指令,還有LVT、miranda 方法等,存盤格式比較復雜,并且概念理解起來也并不是一-件輕松的事情,JVM為Java方法在記憶體中所構建的對等體也明顯更加復雜,
同時,Java方法的決議還承擔了一部分實作面向物件機制的責任,其核心技術便是vtable,只有真正理解了vtable 的實作機制,才能真正理解Java面向物件與多重繼承的原理,
章節簡介
- 方法簽名決議與校驗
- code屬性決議.
- LVT&LVTT
- 創建methodOop
- Java方法屬性復制
- <clinit>與<init>
- 查看運行時位元組碼指令
- C++中的多型與vtable
- Java中的多型實作機制
- vtable特點總結
- vtable機制邏輯驗證

第9章:執行引擎
JVM最核心的技術便是執行引擎,最難的也是執行引擎,要想透徹理解JVM的執行引擎,就必須先理解物理計算機CPU執行運算的機制,本書詳細描述了物理CPU進行取值、譯碼、運算的原理,并從這個點出發,逐步深入講解JVM的執行引擎的運行機制,
章節簡介
- 執行引擎概述
- 指令長度..
- JVM的兩級取值機制
- 取指指令放在哪
- 程式計數器在哪里
- 譯碼
- 堆疊頂快取
- 堆疊式指令集
- 運算元堆疊在哪里.
- 堆疊幀重疊
- entry_ point 例程機器指令
- 執行引擎實戰
- 位元組碼指令實作

第10章:類的生命周期
類的加載機制與生命周期等概念,在各種書籍與各種網路博客里隨處可見,然而對于一個想要真正了解其內部實作的人而言,那些都涉人過淺,本章“撥云見日”,從JVM原始碼的角度,還原出Java類加載的真實機制,以及類生命周期的實作方式,
章節簡介
- 類的生命周期概述
- 類加載——鏡像類與靜態欄位
- Java主類加載機制
- 類加載器的加載機制
- 反射加載機制
- import與new指令
- 類加載器的定義
- 系統類加載器與擴展類加載器創建
- 雙親委派機制與破壞
- 父加載器
- 預加載
- 引導類加載
- 堆疊.上分配與逃逸分析
- TLAB
- 指標碰撞與eden區分配
- 清零
- 偏向鎖
- 壓堆疊與取指

JVM涉及的知識面十分廣闊,因此限于篇幅,本篇并未覆寫JVM的全部內容,總體而言,本篇重點描述了JVM從啟動開始到完成函式執行的詳細機制,讀完本篇,相信你一定能夠明白JVM執行Java程式的底層機制,能夠明白JVM將Java語言一步步轉換為CPU可執行的機器碼的內部機制,以及為此而制定的各種規范的實作之道,例如oop-klass 模型、堆疊分配模型、類加載模型等,
實戰是檢驗自己成果的重要方式
所謂實戰,并不是讓大家空造專案,在這里小編整理了2020最新阿里面試真題,如果換做是你,你又能和面試官過上幾個回合呢?

- JDK、 JRE、JVM 的關系是什么?
- JVM 的記憶體模型以及磁區情況和作用
- JVM 物件創建步驟流程是什么?
- 垃圾回收演算法有幾種型別? 他們對應的優缺點又是什么?
- 類的加載程序是什么?簡單描述一下每個步驟
- JVM 預定義的類加載器有哪幾種?分別什么作用?
- 什么是雙親委派模式?有什么作用?
- 介紹一下 JVM 中垃圾收集器有哪些? 他們特點分別是什么?
- 什么是 Class 檔案? Class 檔案主要的資訊結構有哪些?
- 物件“物件已死” 是什么概念?
- Java 語言怎么實作跨平臺的?
- 詳細介紹一下物件在分帶記憶體區域的分配程序?
- G1 與 CMS 兩個垃圾收集器的對比
- 線上常用的 JVM 引數有哪些?
- 物件什么時候進入老年代?
- 什么是記憶體溢位, 記憶體泄露? 他們的區別是什么?
- 引起類加載操作的行為有哪些?
- 介紹一下 JVM 提供的常用工具
- 什么情況下會出現堆疊溢位
- 說一下強參考、軟參考、弱參考、虛參考以及他們之間和 gc 的關系
如果是你,你能達到什么程度?

后記
學習是一個漫長的程序,只有耐得住寂寞,才能識訓到成功的甘醇!!!
在這里,小編已經將此面試真題和前文的學習檔案打包歸類,有需要深度學習的朋友,請幫忙轉發+關注小編,并私信回復【學習】即可哦~~~
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/30280.html
標籤:其他
