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