<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          教妹學(xué)Java第7講:每個(gè)程序員都應(yīng)該了解的Java 虛擬機(jī)

          共 5778字,需瀏覽 12分鐘

           ·

          2020-10-25 09:57

          hello,小伙伴們,大家好,我是沉默王二,一枚沉默但有趣的程序員。又到了《教妹學(xué) Java》的時(shí)間,很開心,很期待,很舒適,有沒有?這是《教妹學(xué) Java》專欄的第 7 篇文章,我們來談?wù)劇癑ava 虛擬機(jī)”。

          強(qiáng)烈推薦:我在 GitHub 上發(fā)現(xiàn)了一個(gè)寶藏項(xiàng)目,里面羅列了幾百本 Java 經(jīng)典電子書,包含入門、工具、框架、數(shù)據(jù)庫、并發(fā)編程、底層、性能優(yōu)化、設(shè)計(jì)模式、計(jì)算機(jī)網(wǎng)絡(luò)、操作系統(tǒng)、數(shù)據(jù)結(jié)構(gòu)與算法、面試、大數(shù)據(jù)、架構(gòu)等等方面,應(yīng)有盡有,需要的小伙伴可以到 GitHub 上自取:


          https://github.com/itwanger/JavaBooks

          上一篇文章發(fā)表后,就有小伙伴留言說“二哥,你是成功帶妹入坑啊”,我也是被逼的啊。所以專欄名你們也看到了,對(duì),初衷真的是教我妹學(xué) Java。不過,我相信小伙伴們?cè)陂喿x的過程中也一定能感受到思維的樂趣,還能真的學(xué)習(xí)到知識(shí)。

          再次強(qiáng)調(diào),《教妹學(xué) Java》專欄面向的是零基礎(chǔ)的 Java 學(xué)習(xí)者,我希望這個(gè)專欄能夠帶領(lǐng) Java 初學(xué)者輕松邁進(jìn)編程世界的大門,并且能夠讀寫編寫出規(guī)范、有用的 Java 代碼。同時(shí),為后續(xù)的深入學(xué)習(xí)打下堅(jiān)實(shí)的基礎(chǔ)。

          我妹(親妹)今年上大學(xué)了,學(xué)的計(jì)算機(jī)編程,沒成想,她的一名老師竟然是我的讀者,我妹是又驚喜又恐慌,驚喜是她哥我的讀者群體還挺廣泛的嘛,恐慌的是萬一學(xué)不好豈不是很丟他哥的臉?

          為了給妹妹全方位的支援,就有了《教妹學(xué) Java》這個(gè)專欄,希望我妹能通過這個(gè)專欄更快地掌握 Java 這門編程語言。同時(shí),也希望這個(gè)專欄能夠幫助到更多剛?cè)腴T的初學(xué)者,那就爽歪歪了。

          ------我是正兒八經(jīng)的分割線--------

          “二哥,之前的文章里提到 JVM,說實(shí)在的, 我還不知道它到底是干嘛的,你能給我普及一下嗎?”三妹咪了一口麥香可可奶茶后對(duì)我說。

          “三妹,不要擔(dān)心,這篇文章來帶你認(rèn)識(shí)一下什么是 JVM,這也是 Java 中非常重要的一塊知識(shí),每個(gè)程序員都應(yīng)該了解的。”說完最后這句話,我臉上忍不住泛起了一陣羞澀的紅暈。

          看過《Java 發(fā)展簡史》的小伙伴應(yīng)該知道,Sun 在 1991 年成立了一個(gè)由詹姆斯·高斯林(James Gosling)領(lǐng)導(dǎo)的,名為“Green”的項(xiàng)目組,目的是開發(fā)一種能夠在各種消費(fèi)性電子產(chǎn)品上運(yùn)行的程序架構(gòu)。

          一開始,項(xiàng)目組打算使用 C++,但 C++ 無法達(dá)到跨平臺(tái)的要求,比如在 Windows 系統(tǒng)下編譯的 Hello.exe 無法直接拿到 Linux 環(huán)境下執(zhí)行。

          在當(dāng)時(shí),C++ 已經(jīng)非常流行了,但無法跨平臺(tái),只能忍痛割愛了。

          怎么辦呢?

          三妹不知道有沒有聽過直譯器(解釋器)這玩意?(估計(jì)你沒聽過)就是每跑一行代碼就生成機(jī)器碼,然后執(zhí)行,比如說 Python 和 Ruby 用的就是直譯器。在每個(gè)操作系統(tǒng)上裝一個(gè)直譯器就好了,跨平臺(tái)的目的就達(dá)到了。

          但直譯器有個(gè)缺點(diǎn),就是沒法像編譯器那樣對(duì)一些熱點(diǎn)代碼進(jìn)行優(yōu)化,從而讓機(jī)器碼跑得更快一些。

          怎么辦呢?

          來個(gè)結(jié)合體唄,編譯器和直譯器一塊上!

          編譯器負(fù)責(zé)把 Java 源代碼編譯成字節(jié)碼(不清楚的小伙伴可以點(diǎn)擊鏈接查看上一節(jié)),Java 虛擬機(jī)(Java Virtual Machine,簡稱 JVM) 負(fù)責(zé)把字節(jié)碼轉(zhuǎn)換成機(jī)器碼。轉(zhuǎn)換的時(shí)候,可以做一些壓縮或者優(yōu)化,這樣的機(jī)器碼跑起來就快多了。

          不僅跨平臺(tái)的目的達(dá)到了,而且性能得到了優(yōu)化。

          三妹是不是想問,“為什么 Java 虛擬機(jī)會(huì)叫 Java 虛擬機(jī)呢?”

          虛擬機(jī),顧名思義,就是虛擬的機(jī)器(多蒼白的解釋),反正就是看不見摸不著的機(jī)器,把它想象成一個(gè)會(huì)執(zhí)行字節(jié)碼的怪獸吧。

          記得上大學(xué)那會(huì),由于沒有 Linux 環(huán)境,但又需要在上面玩一些命令,于是就在 Windows 上裝 Linux 的虛擬機(jī),這個(gè) JVM 就類似這種東西。

          說白了,就是我們編寫 Java 代碼,編譯 Java 代碼,目的不是讓它在 Linux、Windows 或者 MacOS 上跑,而是在 JVM 上跑。

          說到這,三妹是不是想問,“都有哪些 Java 虛擬機(jī)呢?”來看下面這張思維導(dǎo)圖:

          除了我們經(jīng)常看到,經(jīng)常聽到的 Hotspot VM,還有很多,下面我來簡單介紹一下。

          • Sun Classic:世界上第一款商用 Java 虛擬機(jī),但執(zhí)行效率低下,導(dǎo)致 Java 程序的性能和 C/C++ 存在很大差距,因此給后來者留下了“Java 語言很慢”的刻板印象。

          • Exact VM:為了提升 Classic 的效率,Sun 的虛擬機(jī)團(tuán)隊(duì)曾在 Solaris(Sun 研發(fā)的一款類似 Unix 的操作系統(tǒng))上發(fā)布過這款虛擬機(jī),它的執(zhí)行系統(tǒng)里包含有熱點(diǎn)探測(cè)、即時(shí)編譯等,但不是很成熟。

          Sun Classic 在 JDK 1.4 的時(shí)候被徹底拋棄,而 Exact VM 被拋棄得更早,取代它的正是 HotSpot VM——時(shí)也命也。

          • HotSpot VM:OracleJDK(商用)和 OpenJDK(開源)的默認(rèn)虛擬機(jī),也是目前使用最廣泛的 Java 虛擬機(jī)。

          HotSpot 的技術(shù)優(yōu)勢(shì)就在于熱點(diǎn)代碼探測(cè)技術(shù)(名字就從這來)和準(zhǔn)確式內(nèi)存管理技術(shù),但其實(shí)這兩個(gè)技術(shù)在 Exact VM 中都有體現(xiàn),因此你看起個(gè)好的名字多重要(開玩笑了,這就是命)。

          熱點(diǎn)代碼探測(cè),指的是,通過執(zhí)行計(jì)數(shù)器找出最具有編譯價(jià)值的代碼,然后通知即時(shí)編譯器以方法為單位進(jìn)行編譯,解釋器就可以不再逐行的將字節(jié)碼翻譯成機(jī)器碼,而是將一整個(gè)方法的所有字節(jié)碼翻譯成機(jī)器碼再執(zhí)行。

          這樣的話,效率就提高了很多,對(duì)吧?

          • Mobile VM:Java 在移動(dòng)手機(jī)端(被 Android 和 IOS 二分天下)的發(fā)展并沒有那么成功,因此 Mobile VM 的聲望值比較低。

          • Embedded VM:嵌入式設(shè)備上的虛擬機(jī)。

          • BEA JRockit:曾經(jīng)號(hào)稱是“世界上最快的 Java 虛擬機(jī)”,后來被 Oracle 收購后就沒有聲音了。

          • IBM J9 VM:提起 IBM,基本上所有程序員都知道了,也是個(gè)巨頭,所以他家的虛擬機(jī)也很強(qiáng),在職責(zé)分離和模塊化上做得比 HotSpot 更好。目前已經(jīng)開源給 Eclipse 基金會(huì)。

          • BEA Liquid VM:是 BEA 公司開發(fā)的可以直接運(yùn)行在自家系統(tǒng)上的虛擬機(jī),可以越過操作系統(tǒng)直接和硬件打交道,因此可以更大程度上的發(fā)揮硬件的能力。不過核心用的還是 JRockit,所以伴隨著 JRockit 的消失,Liquid VM 也退出歷史舞臺(tái)了。

          • Azul VM:是 Azul 公司在 HotSpot 基礎(chǔ)上進(jìn)行大量改進(jìn)后的,可以運(yùn)行在 Azul 公司專有硬件上的虛擬機(jī)。2010 年起,Azul 公司的重心從硬件轉(zhuǎn)移到軟件上,并發(fā)布了 Zing 虛擬機(jī),性能方面很強(qiáng)大。

          • Apache Harmony 和 Google Android Dalvik VM 并不是 嚴(yán)格意義上的 Java 虛擬機(jī),但對(duì) Java 虛擬機(jī)的發(fā)展起到了很大的刺激作用。但它們終究沒有熬過時(shí)間。

          • Microsoft JVM:在早期的 Java Applets 年代,微軟為了在 IE 中支持 Applets 開發(fā)了自己的 Java 虛擬機(jī)。你敢相信?Microsoft JVM 只有 Windows 版本,它與 JVM 實(shí)現(xiàn)的“一次編譯,到處運(yùn)行”的理念完全沾不上邊。

          關(guān)鍵是,1997 年 10 月,Sun 公司因?yàn)檫@事把微軟告了,最后微軟賠給了 Sun 公司 2000 萬美金,并且終止了在 Java 虛擬機(jī)方面的發(fā)展。如果,我是說如果,如果微軟保持著對(duì) Java 的熱情,后面還有 .Net 什么事?

          解釋了這么多 Java 虛擬機(jī)后,三妹是不是想問,“Java 虛擬機(jī)長什么樣子呢?”

          Java 虛擬機(jī)雖然是虛擬的,但它的內(nèi)部是可以劃分為:

          • 類加載器(Class Loader)
          • 運(yùn)行時(shí)數(shù)據(jù)區(qū)(Runtime Data Areas)
          • 執(zhí)行引擎(Excution Engine)

          1)類加載器

          類加載器是 Java 虛擬機(jī)的一個(gè)子系統(tǒng),用于加載類文件。每當(dāng)我們運(yùn)行一個(gè) Java 程序,它都會(huì)由類加載器首先加載。

          一般來說,Java 程序員并不需要直接同類加載器進(jìn)行交互。JVM 默認(rèn)的行為就已經(jīng)足夠滿足大多數(shù)情況的需求了。不過,如果遇到了需要和類加載器進(jìn)行交互的情況,而對(duì)類加載器的機(jī)制又不是很了解的話,就不得不花大量的時(shí)間去調(diào)試ClassNotFoundExceptionNoClassDefFoundError 等異常。

          對(duì)于任意一個(gè)類,都需要由它的類加載器和這個(gè)類本身一同確定其在 JVM 中的唯一性。也就是說,如果兩個(gè)類的加載器不同,即使兩個(gè)類來源于同一個(gè)字節(jié)碼文件,那這兩個(gè)類就必定不相等(比如兩個(gè)類的 Class 對(duì)象不 equals)。

          來通過一段簡單的代碼了解下。

          /**
          ?*?@author?微信搜「沉默王二」,回復(fù)關(guān)鍵字?PDF
          ?*/

          public?class?Test?{
          ????public?static?void?main(String[]?args)?{
          ????????ClassLoader?loader?=?Test.class.getClassLoader();
          ????????while?(loader?!=?null)?{
          ????????????System.out.println(loader);
          ????????????loader?=?loader.getParent();
          ????????}
          ????}
          }

          每個(gè) Java 類都維護(hù)著一個(gè)指向定義它的類加載器的引用,通過 類名.class.getClassLoader() 可以獲取到此引用;然后通過 loader.getParent() 可以獲取類加載器的上層類加載器。

          上面這段代碼的輸出結(jié)果如下:

          jdk.internal.loader.ClassLoaders$AppClassLoader@512ddf17
          jdk.internal.loader.ClassLoaders$PlatformClassLoader@2d209079

          第一行輸出為 Test 的類加載器,即應(yīng)用類加載器,它是 jdk.internal.loader.ClassLoaders$AppClassLoader 類的實(shí)例;第二行輸出為平臺(tái)類加載器,是 jdk.internal.loader.ClassLoaders$PlatformClassLoader 類的實(shí)例。那啟動(dòng)類加載器呢?

          按理說,擴(kuò)展類加載器的上層類加載器是啟動(dòng)類加載器,但啟動(dòng)類加載器是虛擬機(jī)的內(nèi)置類加載器,通常表示為 null。

          2)運(yùn)行時(shí)數(shù)據(jù)區(qū)

          來看下面這張圖:

          • PC寄存器(PC Register),也叫程序計(jì)數(shù)器(Program Counter Register),是一塊較小的內(nèi)存空間,它的作用可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的信號(hào)指示器。

          • JVM 棧(Java Virtual Machine Stack),與 PC 寄存器一樣,JVM 棧也是線程私有的。每一個(gè) JVM 線程都有自己的 JVM 棧,這個(gè)棧與線程同時(shí)創(chuàng)建,它的生命周期與線程相同。

          • 本地方法棧(Native Method Stack),JVM 可能會(huì)使用到傳統(tǒng)的棧來支持 Native 方法(使用 Java 語言以外的其它語言[C語言]編寫的方法)的執(zhí)行,這個(gè)棧就是本地方法棧。

          • 堆(Heap),在 JVM 中,堆是可供各條線程共享的運(yùn)行時(shí)內(nèi)存區(qū)域,也是供所有類實(shí)例和數(shù)據(jù)對(duì)象分配內(nèi)存的區(qū)域。

          • 方法區(qū)(Method area),在 JVM 中,被加載類型的信息都保存在方法區(qū)中。包括類型信息(Type Information)和方法列表(Method Tables)。方法區(qū)是所有線程共享的,所以訪問方法區(qū)信息的方法必須是線程安全的。

          • 運(yùn)行時(shí)常量池(Runtime Constant Pool),運(yùn)行時(shí)常量池是每一個(gè)類或接口的常量池在運(yùn)行時(shí)的表現(xiàn)形式,它包括了編譯器可知的數(shù)值字面量,以及運(yùn)行期解析后才能獲得的方法或字段的引用。簡而言之,當(dāng)一個(gè)方法或者變量被引用時(shí),JVM 通過運(yùn)行時(shí)常量區(qū)來查找方法或者變量在內(nèi)存里的實(shí)際地址。

          3)執(zhí)行引擎

          執(zhí)行引擎包含了:

          • 解釋器:讀取字節(jié)碼流,然后執(zhí)行指令。因?yàn)樗且恍幸恍械亟忉尯蛨?zhí)行指令,所以它可以很快地解釋字節(jié)碼,但是執(zhí)行起來會(huì)比較慢(畢竟要一行執(zhí)行完再執(zhí)行下一行)。

          • 即時(shí)(Just-In-Time,JIT)編譯器:即時(shí)編譯器用來彌補(bǔ)解釋器的缺點(diǎn),提高性能。執(zhí)行引擎首先按照解釋執(zhí)行的方式來執(zhí)行,然后在合適的時(shí)候,即時(shí)編譯器把整段字節(jié)碼編譯成本地代碼。然后,執(zhí)行引擎就沒有必要再去解釋執(zhí)行方法了,它可以直接通過本地代碼去執(zhí)行。執(zhí)行本地代碼比一條一條進(jìn)行解釋執(zhí)行的速度快很多。編譯后的代碼可以執(zhí)行的很快,因?yàn)楸镜卮a是保存在緩存里的。

          “三妹,關(guān)于 Java 虛擬機(jī),今天我們就學(xué)到這吧,后面再展開講,怎么樣?”轉(zhuǎn)動(dòng)了一下僵硬的脖子后,我對(duì)三妹說,“Java 虛擬機(jī)是一塊很大很深的內(nèi)容,如果一上來學(xué)太多的話,我怕難倒你。”

          “好的,二哥,我也覺得今天的知識(shí)量夠了,我要好好消化幾天。我會(huì)加油的!”三妹似乎對(duì)未來充滿了希望,這正是我想看到的。

          這是《教妹學(xué) Java》專欄的第 7 篇文章,能看到這里的小伙伴都是最帥的,最美的,升職加薪就是你了?。

          寫這個(gè)專欄的初衷就是為了幫助那些零基礎(chǔ)學(xué) Java,或者自學(xué) Java 感覺特別痛苦,特別難入門的小伙伴。

          另外,我還創(chuàng)建了一些「技術(shù)交流群」,群里氛圍很不錯(cuò),有不少小伙伴會(huì)分享一些校招或者社招經(jīng)驗(yàn),更重要的是,群里時(shí)不時(shí)會(huì)有「紅包」等福利,當(dāng)然,群里不允許任何形式的廣告。掃描下方的二維碼,回復(fù)「加群」即可。

          示例代碼已經(jīng)同步到 GitHub,地址為 github.com/itwanger,也可以點(diǎn)擊閱讀原文進(jìn)行跳轉(zhuǎn),歡迎 star。

          瀏覽 45
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国内色图| 国产永久免费无遮挡被操裸体美女 | 五月丁香婷婷激情 | 日韩三级乱伦 | 国产美女裸身网站 |