作為Java工程師的你曾被傷害過(guò)嗎,?你是否也遇到過(guò)這些問(wèn)題,?
- 運(yùn)行著的線(xiàn)上系統(tǒng)突然卡死,系統(tǒng)無(wú)法訪(fǎng)問(wèn),,甚至直接OOM,!
- 想解決線(xiàn)上JVM GC問(wèn)題,但卻無(wú)從下手,。
- 新項(xiàng)目上線(xiàn),對(duì)各種JVM參數(shù)設(shè)置一臉茫然,,直接默認(rèn)吧然后就GG了
- 每次面試之前都要重新背一遍JVM的一些原理概念性的東西,,然而面試官卻經(jīng)常問(wèn)你在實(shí)際項(xiàng)目中如何調(diào)優(yōu)VM參數(shù),如何解決GC,、OOM等問(wèn)題,,一臉懵逼。
2.開(kāi)發(fā)人員的病態(tài)
- 大部分Java開(kāi)發(fā)人員,,除了會(huì)在項(xiàng)目中使用到與Java平臺(tái)相關(guān)的各種高精尖技術(shù),,對(duì)于Java技術(shù)的核心Java虛擬機(jī)了解甚少。
- 一些有一定工作經(jīng)驗(yàn)的開(kāi)發(fā)人員,,打心眼兒里覺(jué)得SSM,、微服務(wù)等上層技術(shù)才是重點(diǎn),基礎(chǔ)技術(shù)并不重要,,這其實(shí)是一種本末倒置的“病態(tài)”,。如果我們把核心類(lèi)庫(kù)的API比做數(shù)學(xué)公式的話(huà),那么Java虛擬機(jī)的知識(shí)就好比公式的推導(dǎo)過(guò)程,。
- 計(jì)算機(jī)系統(tǒng)體系對(duì)我們來(lái)說(shuō)越來(lái)越遠(yuǎn),,在不了解底層實(shí)現(xiàn)方式的前提下,通過(guò)高級(jí)語(yǔ)言很容易編寫(xiě)程序代碼,。但事實(shí)上計(jì)算機(jī)并不認(rèn)識(shí)高級(jí)語(yǔ)言
架構(gòu)師每天都在思考什么,?
- 應(yīng)該如何讓我的系統(tǒng)更快?
- 如何避免系統(tǒng)出現(xiàn)瓶頸,?
知乎上有條帖子:應(yīng)該如何看招聘信息,,直通年薪50萬(wàn)+?
- 參與現(xiàn)有系統(tǒng)的性能優(yōu)化,,重構(gòu),,保證平臺(tái)性能和穩(wěn)定性
- 根據(jù)業(yè)務(wù)場(chǎng)景和需求,決定技術(shù)方向,,做技術(shù)選型
- 能夠獨(dú)立架構(gòu)和設(shè)計(jì)海量數(shù)據(jù)下高并發(fā)分布式解決方案,,滿(mǎn)足功能和非功能需求
- 解決各類(lèi)潛在系統(tǒng)風(fēng)險(xiǎn),,核心功能的架構(gòu)與代碼編寫(xiě)
- 分析系統(tǒng)瓶頸,解決各種疑難雜癥,,性能調(diào)優(yōu)等
4.為什么學(xué)習(xí)jvm
- 面試的需要(BATJ,、TMD,PKQ等面試都愛(ài)問(wèn))
- 中高級(jí)程序員必備技能:項(xiàng)目管理,、調(diào)優(yōu)的需求
- 追求極客的精神,,比如:垃圾回收算法、JIT(即時(shí)編譯器),、底層原理
5.Java VS C++
- 垃圾收集機(jī)制為我們打理了很多繁瑣的工作,,大大提高了開(kāi)發(fā)的效率,但是,,垃圾收集也不是萬(wàn)能的,,懂得JVM內(nèi)部的內(nèi)存結(jié)構(gòu)、工作機(jī)制,,是設(shè)計(jì)高擴(kuò)展性應(yīng)用和診斷運(yùn)行時(shí)問(wèn)題的基礎(chǔ),,也是Java工程師進(jìn)階的必備能力。
- C語(yǔ)言需要自己來(lái)分配內(nèi)存和回收內(nèi)存,,Java全部交給JVM進(jìn)行分配和回收,。
6.TIOBE 排行榜
TIOBE 排行榜:https://www./tiobe-index/
7.Java 生態(tài)圈
Java是目前應(yīng)用最為廣泛的軟件開(kāi)發(fā)平臺(tái)之一。隨著Java以及Java社區(qū)的不斷壯大Java 也早已不再是簡(jiǎn)簡(jiǎn)單單的一門(mén)計(jì)算機(jī)語(yǔ)言了,,它更是一個(gè)平臺(tái),、一種文化、一個(gè)社區(qū),。
- 作為一個(gè)平臺(tái),,Java虛擬機(jī)扮演著舉足輕重的作用
- Groovy、Scala,、JRuby,、Kotlin等都是Java平臺(tái)的一部分
- 作為一種文化,Java幾乎成為了'開(kāi)源'的代名詞,。
- 第三方開(kāi)源軟件和框架,。如Tomcat、Struts,,MyBatis,,Spring等。
- 就連JDK和JVM自身也有不少開(kāi)源的實(shí)現(xiàn),,如openJDK,、Harmony。
- 作為一個(gè)社區(qū),,Java擁有全世界最多的技術(shù)擁護(hù)者和開(kāi)源社區(qū)支持,,有數(shù)不清的論壇和資料,。從桌面應(yīng)用軟件、嵌入式開(kāi)發(fā)到企業(yè)級(jí)應(yīng)用,、后臺(tái)服務(wù)器,、中間件,都可以看到Java的身影,。其應(yīng)用形式之復(fù)雜,、參與人數(shù)之眾多也令人咋舌。
8.Java的跨平臺(tái)性
- 每個(gè)語(yǔ)言都需要轉(zhuǎn)換成字節(jié)碼文件,,最后轉(zhuǎn)換的字節(jié)碼文件都能通過(guò)Java虛擬機(jī)進(jìn)行運(yùn)行和處理
- 隨著Java7的正式發(fā)布,,Java虛擬機(jī)的設(shè)計(jì)者們通過(guò)JSR-292規(guī)范基本實(shí)現(xiàn)在Java虛擬機(jī)平臺(tái)上運(yùn)行非Java語(yǔ)言編寫(xiě)的程序。
- Java虛擬機(jī)根本不關(guān)心運(yùn)行在其內(nèi)部的程序到底是使用何種編程語(yǔ)言編寫(xiě)的,,它只關(guān)心“字節(jié)碼”文件,。也就是說(shuō)Java虛擬機(jī)擁有語(yǔ)言無(wú)關(guān)性,并不會(huì)單純地與Java語(yǔ)言“終身綁定”,,只要其他編程語(yǔ)言的編譯結(jié)果滿(mǎn)足并包含Java虛擬機(jī)的內(nèi)部指令集、符號(hào)表以及其他的輔助信息,,它就是一個(gè)有效的字節(jié)碼文件,,就能夠被虛擬機(jī)所識(shí)別并裝載運(yùn)行。
9.字節(jié)碼
- 我們平時(shí)說(shuō)的java字節(jié)碼,,指的是用java語(yǔ)言編譯成的字節(jié)碼,。準(zhǔn)確的說(shuō)任何能在jvm平臺(tái)上執(zhí)行的字節(jié)碼格式都是一樣的。所以應(yīng)該統(tǒng)稱(chēng)為:
jvm字節(jié)碼 ,。 - 不同的編譯器,,可以編譯出相同的字節(jié)碼文件,字節(jié)碼文件也可以在不同的JVM上運(yùn)行,。
- Java虛擬機(jī)與Java語(yǔ)言并沒(méi)有必然的聯(lián)系,,它只與特定的二進(jìn)制文件格式——Class文件格式所關(guān)聯(lián),Class文件中包含了Java虛擬機(jī)指令集(或者稱(chēng)為字節(jié)碼,、Bytecodes)和符號(hào)表,,還有一些其他輔助信息。
10.多語(yǔ)言混合編程
Java平臺(tái)上的多語(yǔ)言混合編程正成為主流,,通過(guò)特定領(lǐng)域的語(yǔ)言去解決特定領(lǐng)域的問(wèn)題是當(dāng)前軟件開(kāi)發(fā)應(yīng)對(duì)日趨復(fù)雜的項(xiàng)目需求的一個(gè)方向 ,。- 試想一下,在一個(gè)項(xiàng)目之中,,并行處理用Clojure語(yǔ)言編寫(xiě),,展示層使用JRuby/Rails,中間層則是Java,,每個(gè)應(yīng)用層都將使用不同的編程語(yǔ)言來(lái)完成,,而且,,接口對(duì)每一層的開(kāi)發(fā)者都是透明的,各種語(yǔ)言之間的交互不存在任何困難,,就像使用自己語(yǔ)言的原生API一樣方便,,因?yàn)樗鼈冏罱K都運(yùn)行在一個(gè)虛擬機(jī)之上。
- 對(duì)這些運(yùn)行于Java虛擬機(jī)之上,、Java之外的語(yǔ)言,,來(lái)自系統(tǒng)級(jí)的、底層的支持正在迅速增強(qiáng),,以JSR-292為核心的一系列項(xiàng)目和功能改進(jìn)(如DaVinci Machine項(xiàng)目,、Nashorn引擎、InvokeDynamic指令,、java.lang.invoke包等),,
推動(dòng)Java虛擬機(jī)從'Java語(yǔ)言的虛擬機(jī)'向'多語(yǔ)言虛擬機(jī)'的方向發(fā)展 。
11.自己寫(xiě)個(gè)jvm
- Java虛擬機(jī)非常復(fù)雜,,要想真正理解它的工作原理,,最好的方式就是自己動(dòng)手編寫(xiě)一個(gè)!
- 自己動(dòng)手寫(xiě)一個(gè)Java虛擬機(jī),,難嗎,?
- 天下事有難易乎?為之,,則難者亦易矣,;不為,則易者亦難矣
12.Java的重大事件
- 1990年,,在Sun計(jì)算機(jī)公司中,,由Patrick Naughton、MikeSheridan及James Gosling領(lǐng)導(dǎo)的小組Green Team,,開(kāi)發(fā)出的新的程序語(yǔ)言,,命名為Oak,后期命名為Java
- 1995年,,Sun正式發(fā)布Java和HotJava產(chǎn)品,,Java首次公開(kāi)亮相。
- 1996年1月23日Sun Microsystems發(fā)布了JDK 1.0,。
- 1998年,,JDK1.2版本發(fā)布。同時(shí),,Sun發(fā)布了JSP/Servlet,、EJB規(guī)范,以及將Java分成了J2EE、J2SE和J2ME,。這表明了Java開(kāi)始向企業(yè),、桌面應(yīng)用和移動(dòng)設(shè)備應(yīng)用3大領(lǐng)域挺進(jìn)。
- 2000年,,JDK1.3發(fā)布,,Java HotSpot Virtual Machine正式發(fā)布,成為Java的默認(rèn)虛擬機(jī),。
- 2002年,,JDK1.4發(fā)布,古老的Classic虛擬機(jī)退出歷史舞臺(tái),。
- 2003年年底,,Java平臺(tái)的scala正式發(fā)布,同年Groovy也加入了Java陣營(yíng),。
- 2004年,,JDK1.5發(fā)布。同時(shí)JDK1.5改名為JavaSE5.0,。
- 2006年,,JDK6發(fā)布。同年,,Java開(kāi)源并建立了OpenJDK,。順理成章,Hotspot虛擬機(jī)也成為了OpenJDK中的默認(rèn)虛擬機(jī),。
- 2007年,Java平臺(tái)迎來(lái)了新伙伴Clojure,。
- 2008年,,oracle收購(gòu)了BEA,得到了JRockit虛擬機(jī),。
- 2009年,,Twitter宣布把后臺(tái)大部分程序從Ruby遷移到Scala,這是Java平臺(tái)的又一次大規(guī)模應(yīng)用,。
- 2010年,,Oracle收購(gòu)了Sun,獲得Java商標(biāo)和最真價(jià)值的HotSpot虛擬機(jī),。此時(shí),,Oracle擁有市場(chǎng)占用率最高的兩款虛擬機(jī)HotSpot和JRockit,并計(jì)劃在未來(lái)對(duì)它們進(jìn)行整合:HotRockit
- 2011年,,JDK7發(fā)布,。在JDK1.7u4中,正式啟用了新的垃圾回收器G1。
- 2017年,,JDK9發(fā)布,。將G1設(shè)置為默認(rèn)GC,替代CMS
- 同年,,IBM的J9開(kāi)源,,形成了現(xiàn)在的Open J9社區(qū)
- 2018年,Android的Java侵權(quán)案判決,,Google賠償Oracle計(jì)88億美元
- 同年,,Oracle宣告JavagE成為歷史名詞JDBC、JMS,、Servlet贈(zèng)予Eclipse基金會(huì)
- 同年,,JDK11發(fā)布,LTS版本的JDK,,發(fā)布革命性的ZGC,,調(diào)整JDK授權(quán)許可
- 2019年,JDK12發(fā)布,,加入RedHat領(lǐng)導(dǎo)開(kāi)發(fā)的Shenandoah GC
13.1 虛擬機(jī)概念
所謂虛擬機(jī)(Virtual Machine),,就是一臺(tái)虛擬的計(jì)算機(jī) 。它是一款軟件 ,,用來(lái)執(zhí)行一系列虛擬計(jì)算機(jī)指令,。大體上,虛擬機(jī)可以分為系統(tǒng)虛擬機(jī) 和程序虛擬機(jī) ,。
- 大名鼎鼎的Virtual Box,,VMware就屬于系統(tǒng)虛擬機(jī),它們完全是對(duì)物理計(jì)算機(jī)的仿真,,提供了一個(gè)可運(yùn)行完整操作系統(tǒng)的軟件平臺(tái),。
- 程序虛擬機(jī)的典型代表就是
Java虛擬機(jī) ,它專(zhuān)門(mén)為執(zhí)行單個(gè)計(jì)算機(jī)程序而設(shè)計(jì),,在Java虛擬機(jī)中執(zhí)行的指令我們稱(chēng)為Java字節(jié)碼指令,。 - 無(wú)論是系統(tǒng)虛擬機(jī)還是程序虛擬機(jī),在上面運(yùn)行的軟件都被限制于虛擬機(jī)提供的資源中,。
13.2 Java虛擬機(jī)
- Java虛擬機(jī)是一臺(tái)執(zhí)行Java字節(jié)碼的虛擬計(jì)算機(jī),,它擁有獨(dú)立的運(yùn)行機(jī)制,其運(yùn)行的Java字節(jié)碼也未必由Java語(yǔ)言編譯而成,。
- JVM平臺(tái)的各種語(yǔ)言可以共享Java虛擬機(jī)帶來(lái)的跨平臺(tái)性,、優(yōu)秀的垃圾回器,以及可靠的即時(shí)編譯器,。
- Java技術(shù)的核心就是Java虛擬機(jī)(JVM,,Java Virtual Machine),因?yàn)樗械腏ava程序都運(yùn)行在Java虛擬機(jī)內(nèi)部。
- Java虛擬機(jī)就是二進(jìn)制字節(jié)碼的運(yùn)行環(huán)境,,負(fù)責(zé)裝載字節(jié)碼到其內(nèi)部,,解釋/編譯為對(duì)應(yīng)平臺(tái)上的機(jī)器指令執(zhí)行。每一條Java指令,,Java虛擬機(jī)規(guī)范中都有詳細(xì)定義,,如怎么取操作數(shù),怎么處理操作數(shù),,處理結(jié)果放在哪里,。
特點(diǎn)
一次編譯,到處運(yùn)行 自動(dòng)內(nèi)存管理 自動(dòng)垃圾回收功能
14.jvm的位置
JVM是運(yùn)行在操作系統(tǒng)之上的,,它與硬件沒(méi)有直接的交互
Java的體系結(jié)構(gòu)
15.jvm的整體結(jié)構(gòu)
HotSpot VM 是目前市面上高性能虛擬機(jī)的代表作之一,。- 它采用解釋器與即時(shí)編譯器并存的架構(gòu)。
- 在今天,,Java程序的運(yùn)行性能早已脫胎換骨,,已經(jīng)達(dá)到了可以和C/C++程序一較高下的地步。
- 執(zhí)行引擎包含三部分:
解釋器 ,,即時(shí)編譯器 ,,垃圾回收器
16.Java代碼執(zhí)行流程
17.JVM架構(gòu)模型
Java編譯器輸入的指令流基本上是一種基于棧的指令集架構(gòu) ,另外一種指令集架構(gòu)則是基于寄存器的指令集架構(gòu) ,。具體來(lái)說(shuō):這兩種架構(gòu)之間的區(qū)別:
- 基于棧式架構(gòu)的特點(diǎn)
- 設(shè)計(jì)和實(shí)現(xiàn)更簡(jiǎn)單,,適用于資源受限的系統(tǒng)
- 避開(kāi)了寄存器的分配難題:使用零地址指令方式分配
- 指令流中的指令大部分是零地址指令,其執(zhí)行過(guò)程依賴(lài)于
操作棧 ,。指令集更小,,編譯器容易實(shí)現(xiàn) - 不需要硬件支持,可移植性更好,,更好
實(shí)現(xiàn)跨平臺(tái) - 基于寄存器架構(gòu)的特點(diǎn)
- 典型的應(yīng)用是x86的二進(jìn)制指令集:比如傳統(tǒng)的PC以及Android的Davlik虛擬機(jī),。
- 指令集架構(gòu)則
完全依賴(lài)硬件 ,與硬件的耦合度高,,可移植性差 性能優(yōu)秀和執(zhí)行更高效 - 花費(fèi)更少的指令去完成一項(xiàng)操作
- 在大部分情況下,
基于寄存器架構(gòu)的指令集往往都以一地址指令,、二地址指令和三地址指令為主 ,,而基于棧式架構(gòu)的指令集卻是以零地址指令為主
17.1 兩種架構(gòu)的舉例
同樣執(zhí)行2+3這種邏輯操作,其指令分別如下:
- 基于棧的計(jì)算流程(以Java虛擬機(jī)為例)
iconst_2 //常量2入棧
istore_1
iconst_3 // 常量3入棧
istore_2
iload_1
iload_2
iadd //常量2/3出棧,,執(zhí)行相加
istore_0 // 結(jié)果5入棧
mov eax,2 //將eax寄存器的值設(shè)為1
add eax,3 //使eax寄存器的值加3
17.2 反編譯字節(jié)碼文件
/**
* @author xiexu
* @create 2020-11-18 10:14 上午
*/
public class StackStruTest {
public static void main(String[] args) {
int i = 2;
int j = 3;
int k = i + j;
}
}
javap -v StackStruTest.class
反編譯得到的指令
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: iconst_2 // 將常量 2 壓入棧中
1: istore_1 // 將常量 2 保存至變量 i 中
2: iconst_3 // 將常量 3 壓入棧中
3: istore_2 // 將常量 3 保存至變量 j 中
4: iload_1 // 加載變量 i
5: iload_2 // 加載變量 j
6: iadd // 執(zhí)行累加操作
7: istore_3 // 加法結(jié)果保存在變量 k 中
8: return
LineNumberTable:
line 10: 0
line 11: 2
line 12: 4
line 13: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 args [Ljava/lang/String;
2 7 1 i I
4 5 2 j I
8 1 3 k I
}
17.3 總結(jié)
- 由于跨平臺(tái)性的設(shè)計(jì),,Java的指令都是根據(jù)棧來(lái)設(shè)計(jì)的。不同平臺(tái)CPU架構(gòu)不同,,所以不能設(shè)計(jì)為基于寄存器的,。優(yōu)點(diǎn)是跨平臺(tái),指令集小,編譯器容易實(shí)現(xiàn),,缺點(diǎn)是性能下降,,實(shí)現(xiàn)同樣的功能需要更多的指令
- 時(shí)至今日,盡管嵌入式平臺(tái)已經(jīng)不是Java程序的主流運(yùn)行平臺(tái)了(準(zhǔn)確來(lái)說(shuō)應(yīng)該是HotSpot VM的宿主環(huán)境已經(jīng)不局限于嵌入式平臺(tái)了),,那么為什么不將架構(gòu)更換為基于寄存器的架構(gòu)呢,?
- 因?yàn)榛跅5募軜?gòu)跨平臺(tái)性好、指令集小,,雖然相對(duì)于基于寄存器的架構(gòu)來(lái)說(shuō),,基于棧的架構(gòu)編譯得到的指令更多,執(zhí)行性能也不如基于寄存器的架構(gòu)好,,但考慮到其跨平臺(tái)性與移植性,,我們還是選用棧的架構(gòu)
棧:跨平臺(tái)性、指令集小,、指令多,;執(zhí)行性能比寄存器差
- 虛擬機(jī)的啟動(dòng)
- Java虛擬機(jī)的啟動(dòng)是通過(guò)
引導(dǎo)類(lèi)加載器 (bootstrap class loader)創(chuàng)建一個(gè)初始類(lèi)(initial class)來(lái)完成的,這個(gè)類(lèi)是由虛擬機(jī)的具體實(shí)現(xiàn)指定的,。 - 虛擬機(jī)的執(zhí)行
- 一個(gè)運(yùn)行中的Java虛擬機(jī)有著一個(gè)清晰的任務(wù):執(zhí)行Java程序
- 程序開(kāi)始執(zhí)行時(shí)他才運(yùn)行,,程序結(jié)束時(shí)他就停止
執(zhí)行一個(gè)所謂的Java程序的時(shí)候,真真正正在執(zhí)行的是一個(gè)叫做Java虛擬機(jī)的進(jìn)程 - 虛擬機(jī)的退出
- 程序正常執(zhí)行結(jié)束
- 程序在執(zhí)行過(guò)程中遇到了異?;蝈e(cuò)誤而異常終止
- 由于操作系統(tǒng)用現(xiàn)錯(cuò)誤而導(dǎo)致Java虛擬機(jī)進(jìn)程終止
- 某線(xiàn)程調(diào)用Runtime類(lèi)或
System類(lèi)的exit( ) 方法,,或Runtime類(lèi)的halt( ) 方法,并且Java安全管理器也允許這次exit( )或halt( )操作,。 - 除此之外,,JNI(Java Native Interface)規(guī)范描述了用JNI Invocation API來(lái)加載或卸載 Java虛擬機(jī)時(shí),Java虛擬機(jī)的退出情況,。
|