閱讀本文大概需要 5.6 分鐘
前言
在 Java 開發(fā)中,我們經(jīng)常會提到 JVM次企。我們知道 JVM 是 Java 虛擬機虽画,但是它的運行原理是什么?它的內(nèi)存結(jié)構(gòu)是什么贩据?如何進行優(yōu)化栋操?如何去定位問題?面試中遇到 JVM 問題如何回答饱亮?
接下來我會開啟 JVM 的章節(jié)矾芙,為大家一一解答上面的問題。現(xiàn)在就開啟我們的 JVM 學習之路吧近上!
什么是 JVM剔宪?
面試官:什么是 JVM?
小李:JVM(Java Virtual Machine)是 Java 虛擬機,用于運行 Java 編譯后的二進制字節(jié)碼歼跟,最后生成機器指令和媳。(心里一想,簡簡單單)
面試官:那為什么 Java 研發(fā)體系需要 JVM哈街?你對 JVM 的運行原理了解多少留瞳?我們寫的 Java 代碼到底是如何運行起來的?
小李:嗯骚秦。她倘。。就是作箍。硬梁。。嗯胞得。荧止。。是那個阶剑。跃巡。。嗯牧愁。素邪。。
面試官:面試就到這里了猪半,先回去等通知吧兔朦。
小李:好的!(哭著回答)
這里面試官對小李進行三連問:
為什么 Java 研發(fā)體系需要 JVM磨确?
你對 JVM 的運行原理了解多少沽甥?
我們寫的 Java 代碼到底是如何運行起來的?
這套組合拳看似很厲害俐填,其實就是軍體拳安接。
如果想完美的練這套軍體拳,不英融,是完美的回答這三個問題盏檐,就需要首先要了解 JVM 是什么?它和 Java 是什么關系驶悟?又和 JDK 有什么淵源胡野?那要弄清楚這些問題,就需要從三個維度去思考:
JVM 和操作系統(tǒng)的關系痕鳍;
JVM 硫豆、JRE龙巨、JDK 的關系;
Java 虛擬機規(guī)范和 Java 語言規(guī)范的關系熊响。
弄清楚這這幾者的關系旨别,我們再通過一個簡單代碼示例來看一個 Java 程序到底是如何執(zhí)行的。
JVM 和 操作系統(tǒng)的關系
我們知道煉制一把牛逼的大寶劍汗茄,不僅需要上等的技術(shù)秸弛,還需要一鼎經(jīng)百煉的劍爐。而工程師就相當于鑄劍的劍師洪碳,JVM 便是劍爐递览。
JVM 就是我們耳熟能詳?shù)?Java 虛擬機。它能識別 .class 后綴文件瞳腌,并且能夠解析它的指令绞铃,最終調(diào)用操作系統(tǒng)上的函數(shù),完成我們想要的操作嫂侍。
Java 程序和 C++ 程序有什么不同呢儿捧?這里用兩張圖進行說明。
對比兩張圖可以看到 C++ 開發(fā)的程序可以翻譯成操作系統(tǒng)能識別的 .exe 文件吵冒。而 Java 程序需要通過 javac 編譯成 .class 文件之后纯命,然后由 JVM 負責調(diào)用系統(tǒng)函數(shù)執(zhí)行程序,操作系統(tǒng)并不認識 .class 文件痹栖。
那讀者就勸小李了,轉(zhuǎn) C++ 開發(fā)吧瞭空,這 Java 還搞了一個處于程序和操作系統(tǒng)的虛擬機揪阿,不像 C++ 編譯后直接在操作系統(tǒng)上運行,肯定不是啥好玩意咆畏。
我就知道你們壞的很南捂,知道 JVM 的過人之處,還不告訴小李旧找。那我給小李講講 JVM 的過人之處:
Java 是一門抽象度特別高的語言溺健,提供了自動內(nèi)存管理等一系列的特性。這些特性在操作系統(tǒng)上基本上是無望了钮蛛,所以就需要 JVM 進行一番轉(zhuǎn)換鞭缭。
經(jīng)過上面的介紹,我們可以做如下的類比:
JVM:等同于操作系統(tǒng)魏颓;
Java 字節(jié)碼:等同于匯編語言岭辣。
Java 字節(jié)碼還是比較容易讀懂,從側(cè)面上也證明了 Java 語言的抽象程度高甸饱。我們可以認為 JVM 是一個翻譯器沦童,會持續(xù)不斷的翻譯執(zhí)行 Java 字節(jié)碼仑濒,然后調(diào)用真正的操作系統(tǒng)函數(shù),這些操作系統(tǒng)函數(shù)是與平臺息息相關的偷遗。
可以把 JVM 想象一個有道詞典墩瞳,.class 文件是英文,而輸出的結(jié)果是中文氏豌。有道詞典有 windows版本矗烛,也有 Linux 版本,內(nèi)部具體的實現(xiàn)肯定不同箩溃,但最終都會得到相同的結(jié)果瞭吃,這樣就好理解一些了)
當有個 JVM 這個抽象層,就可以實現(xiàn)跨平臺了涣旨。JVM 只需要正確執(zhí)行 .class 文件歪架,就可以運行在 Linux、Windos霹陡、MacOS 等平臺了和蚪。
Java 跨平臺的意義在于一次編譯,處處運行烹棉,這里 JVM 功不可沒攒霹。比如在 Maven 倉庫下載的 jar 包就可以到處運行,不需要在每個平臺上再編譯一次浆洗。
我們來概括 JVM 與操作系統(tǒng)之間的關系:
JVM 上承開發(fā)語言催束,下接操作系統(tǒng),它的中間接口就是字節(jié)碼伏社。
JVM抠刺、JRE、JDK 的關系
通過上面的學習摘昌,我們了解到 JVM 是 Java 程序能夠運行的核心速妖。但是我們要知道,JVM 自己什么也干不了聪黎,你需要給它提供原料(.class 文件)罕容。俗話說:巧婦難為無米之炊。JVM 功能雖然強大稿饰,但還是需要為它提供 .class 文件锦秒。
但是僅靠 JVM 是無法完成一次編譯,到處運行的湘纵。它需要一個基本的類庫脂崔,比如怎么操作文件、怎么連接網(wǎng)絡梧喷、怎么教你出拳(小李已瘋)等砌左。而 Java 體系會一次性將 JVM 運行所需的類庫都傳遞給它脖咐。JVM 標準加上基本類庫就組成了 Java 的運行環(huán)境,就是 JRE (Java Runtime Enviroment)
JVM + 基本類庫 = JRE
那 JDK 又是什么呢汇歹?
JDK 全稱 Java Development Kit屁擅,Kit 是裝備的意思。所以 JDK 不僅包含 JRE产弹,還有一些小工具派歌,比如 javac拓轻、java黍少、jar等。
JRE + javac/java/jar 等指令工具 = JDK
JVM谈况、JRE斤斧、JDK 它們?nèi)咧g的關系早抠,可以用一個包含關系表示。
- JDK > JRE > JVM
Java 虛擬機規(guī)范和 Java 語言規(guī)范的關系
從廣義上來講撬讽,JVM 是一種規(guī)范蕊连,它是最為官方、準確的文檔游昼;狹義上來講甘苍,由于我們使用 Hotspot 更多一些,所以我們在談到這個概念時烘豌,會將他們等同起來载庭。
如果再加我們平常使用的 Java 語言,可以得到下面一張圖扇谣。
左邊是 Java 虛擬機規(guī)范昧捷,為字節(jié)碼的解析提供一個環(huán)境。右邊是 Java 語法規(guī)范罐寨,比如 switch、for序矩、泛型鸯绿、lambda 等相關的程序,最終都會編譯成字節(jié)碼簸淀。而字節(jié)碼是鏈接左右兩部分的橋梁瓶蝴。
如果 .class 文件的規(guī)格是不變的,這兩部分是可以獨立進行優(yōu)化的租幕。But 沒有如果舷手,現(xiàn)在都已經(jīng)到 Java 13 了,為了支持更多的特性劲绪,肯定會增加一些字節(jié)碼指令男窟。
此刻優(yōu)秀的小李提出了一個讓人深思的問題:
如果我不學習 JVM盆赤,會影響我寫 Java 代碼么?
理論上歉眷,這兩者沒有必然的聯(lián)系牺六。他們之間通過 .class 文件進行交互,即使你不了解 JVM汗捡,也能夠?qū)懘蠖鄶?shù)的 Java 代碼淑际。就像你是寫 C++ 代碼一樣,并不需要特別深入的了解操作系統(tǒng)的底層是如何實現(xiàn)的扇住。
那我還學個錘子春缕!瞬間關了該頁面。
客官別走艘蹋,還有但是沒說呢锄贼。
但是,如果你想要寫一些比較精巧簿训、效率比較高的代碼咱娶,就需要了解一些執(zhí)行層面的知識了。了解 JVM强品,主要用在調(diào)優(yōu)以及故障排查上面膘侮,你會對運行中的各種資源分配,有一個比較全面的掌控的榛。(是不是內(nèi)心還有點小期待呢G砹恕)
Java 代碼到底是如何運行起來的
最后,我們簡單看一下 Java 程序的執(zhí)行過程夫晌,了解下它到底是如何運行起來的雕薪。
這里的 Java 程序是文本格式的。比如下面這段 HelloXiaoli.java晓淀,它遵循的就是 Java 語言規(guī)范所袁。其中,我們調(diào)用的 System.out 等模塊凶掰,就是 JRE 提供的類庫燥爷。
通過 JDK 的工具 javac 進行編譯后,就會產(chǎn)生 HelloWorld 的字節(jié)碼懦窘。
javac HelloXiaoli.java
Java 字節(jié)碼是溝通 JVM 和 Java 程序的橋梁前翎,下面使用 javap 來看一下字節(jié)碼到底長什么樣子。javap基本使用
javap -verbose HelloXiaoli.class
0 getstatic #2 <java/lang/System.out>
3 ldc #3 <Hello Xiaoli>
5 invokevirtual #4 <java/io/PrintStream.println>
8 return
Java 虛擬機采用基于棧的架構(gòu)(為什么基于棧的架構(gòu)詳見:JVM 體系結(jié)構(gòu)與工作方式)畅涂,其指令由操作碼和操作數(shù)組成港华。這些字節(jié)碼指令,就叫做 opcode午衰。其中立宜,getstatic冒萄、ldc、invokeevirtual赘理、return 等宦言,就是 opcode。
我們繼續(xù)使用 hexdump 看一下字節(jié)碼的二進制內(nèi)容hexdump 命令
b2 00 02 12 03 b6 00 04 b1
我們可以看一下它們的對應關系商模。JVM 字節(jié)碼對照表
0xb2 getstatic 獲取靜態(tài)字段的值
0x12 ldc 常量池中的常量值入棧
0xb6 invokevirtual 運行時方法綁定調(diào)用方法
0xb1 return void 函數(shù)返回
opcode 是一個字節(jié)的長度(0~255)奠旺,意味著指令集的操作碼個數(shù)不能超過 256 條。緊跟在 opcode 后面的是被操作數(shù)施流。比如 b2 00 02响疚,就代表了 getstatic #2 。
JVM 就是靠解析這些 opcode 和 操作數(shù)來完成程序的執(zhí)行的瞪醋,當我們使用 Java 命令運行 .class 文件的時候忿晕,實際上就相當于啟動了一個 JVM 進程。
JVM 會翻譯這些字節(jié)碼银受,它有兩種執(zhí)行方式:
解釋執(zhí)行践盼,將 opcode + 操作數(shù)翻譯成機器代碼;
JIT宾巍,即時編譯咕幻,它會在一定條件下將字節(jié)碼翻譯成機器碼之后再執(zhí)行。
.class 文件會被加載肄程、存放到 metaspace 中,等待被調(diào)用选浑,這里會有一個類加載器的概念蓝厌。
JVM 的程序運行,都是在棧上完成的古徒,這和其他普通程序的執(zhí)行是類似的拓提,分為堆和棧。比如我們程序運行到了 main 方法隧膘,就會給它分配一個棧幀崎苗。當推出方法體時,會彈出相應的棧幀舀寓。其實,大多數(shù)字節(jié)碼指令肌蜻,就是不斷的對棧幀進行操作互墓。
而其它大塊數(shù)據(jù),是存放在堆上的蒋搜。Java 在內(nèi)存劃分上會更為細致篡撵,關于這些概念判莉,會在后面的章節(jié)中詳細介紹。
我們看下面的圖育谬,JVM 部分是我們系列需要講解的部分券盅。
小結(jié)
上面講了這么多,讓我們再回頭看看面試官提問的三個問題膛檀。
- 為什么 Java 研發(fā)系統(tǒng)需要 JVM锰镀?
因為 Java 是一門抽象的語言,并且有自動內(nèi)存管理機制咖刃。而操作系統(tǒng)無法去進行自動垃圾回收等操作泳炉,所以就有了虛擬機。虛擬機可以對字節(jié)碼加載嚎杨、自動垃圾回收花鹅、并發(fā)等。而 JVM 只是一個規(guī)范枫浙,定義了 .class 文件的結(jié)構(gòu)刨肃、加載機制、數(shù)據(jù)存儲箩帚、運行時棧等諸多內(nèi)容真友,最常用的 JVM 實現(xiàn)就是 Hotspot。
- 你對 JVM 的運行原理了解多少膏潮?
JVM 的生命周期是和 Java 程序的運行一樣锻狗,當程序運行結(jié)束,JVM 實例也就跟著消失了焕参。具體的運行原理轻纪,會在后續(xù)文章中詳細介紹,請關注小李哦叠纷!
- 我們寫的 Java 代碼到底是如何運行起來的刻帚?
Java 程序通過 javac 編譯成 .class 文件,然后虛擬機將其加載到元數(shù)據(jù)區(qū)涩嚣,執(zhí)行引擎將會通過混合模式執(zhí)行這些字節(jié)碼崇众。執(zhí)行時,會翻譯成操作系統(tǒng)相關的函數(shù)航厚。
過程如下:Java 文件->編譯器->字節(jié)碼->JVM->機器碼
總結(jié)
本篇文章從三個角度了解了 JVM 在 Java 研發(fā)體系中的位置顷歌,并以一個簡單的程序,看了下一個 Java 程序的執(zhí)行過程幔睬。
我們說的 JVM眯漩,狹義上指的就是 HotSpot。如果沒有特殊說明,我們都以 HotSpot 為準赦抖。
我們知道 Java 之所以跨平臺舱卡,就是由于 JVM 的存在。Java 的字節(jié)碼队萤,是溝通 Java 語言與 JVM 的橋梁轮锥,同時也是溝通 JVM 與操作系統(tǒng)的橋梁。
JVM 是一個非常小的集合要尔,我們常說的 Java 運行時環(huán)境舍杜,也就是 JRE 包含 JVM 和一部分基礎類庫。如果加上我們常用的一些開發(fā)工具盈电,就構(gòu)成了整個 JDK蝴簇。
Java 虛擬機棧采用基于棧的架構(gòu),有比較豐富的 opcode匆帚。這些字節(jié)碼可以解釋執(zhí)行熬词,也可以編譯成機器碼,運行在底層硬件上吸重,可以說 JVM 是一種混合執(zhí)行的策略互拾。
留兩道思考題給大家:
棧上都會有哪些數(shù)據(jù)?
垃圾回收會發(fā)生在什么地方嚎幸?
思考題我會在后面的章節(jié)為大家一一解答颜矿。
參考
http://pc-shop.xiaoe-tech.com/appcCrwMYBx6232/video_details?id=v_5e14662379d00_UAifIZpt