<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      在各自崗位上盡職盡責,無需豪言壯語,默默行動會詮釋一切。這世界,雖然沒有絕對的公平,但是努力就會增加成功和變好的可能性!而這帶著未知變量的可能性,就足以讓我們普通人拼命去爭取了。
      歡迎來到~一支會記憶的筆~博客主頁

      Java代碼是怎么運行的

       

      前言....

      作為一名 Java 程序員,你應該知道,Java 代碼有很多種不同的運行方式。比如說可以在開發工具中運行,可以雙擊執行 jar 文件運行,也可以在命令行中運行,甚至可以在網頁中運行。當然,這些執行方式都離不開 JRE,也就是 Java 運行時環境。實際上,JRE 僅包含運行 Java 程序的必需組件,包括 Java 虛擬機以及 Java 核心類庫等。我們 Java 程序員經常接觸到的 JDK(Java 開發工具包)同樣包含了 JRE,并且還附帶了一系列開發、診斷工具。

      然而,運行 C++ 代碼則無需額外的運行時。我們往往把這些代碼直接編譯成 CPU 所能理解的代碼格式,也就是機器碼。

      比如下圖的中間列,就是用 C 語言寫的 Helloworld 程序的編譯結果。可以看到,C 程序編譯而成的機器碼就是一個個的字節,它們是給機器讀的。那么為了讓開發人員也能夠理解,我們可以用反匯編器將其轉換成匯編代碼(如下圖的最右列所示)。

      ; 最左列是偏移;中間列是給機器讀的機器碼;最右列是給人讀的匯編代碼
      0x00:  55                    push   rbp
      0x01:  48 89 e5              mov    rbp,rsp
      0x04:  48 83 ec 10           sub    rsp,0x10
      0x08:  48 8d 3d 3b 00 00 00  lea    rdi,[rip+0x3b] 
                                          ; 加載 "Hello, World!\n"
      0x0f:  c7 45 fc 00 00 00 00  mov    DWORD PTR [rbp-0x4],0x0
      0x16:  b0 00                 mov    al,0x0
      0x18:  e8 0d 00 00 00        call   0x12
                                          ; 調用 printf 方法
      0x1d:  31 c9                 xor    ecx,ecx
      0x1f:  89 45 f8              mov    DWORD PTR [rbp-0x8],eax
      0x22:  89 c8                 mov    eax,ecx
      0x24:  48 83 c4 10           add    rsp,0x10
      0x28:  5d                    pop    rbp
      0x29:  c3                    ret

      為什么 Java 要在虛擬機中運行呢,Java 虛擬機具體又是怎樣運行 Java 代碼的呢,它的運行效率又如何呢?

      為什么 Java 要在虛擬機里運行?

      Java 作為一門高級程序語言,它的語法非常復雜,抽象程度也很高。因此,直接在硬件上運行這種復雜的程序并不現實。所以呢,在運行 Java 程序之前,我們需要對其進行一番轉換。

      這個轉換具體是怎么操作的呢?當前的主流思路是這樣子的,設計一個面向 Java 語言特性的虛擬機,并通過編譯器將 Java 程序轉換成該虛擬機所能識別的指令序列,也稱 Java 字節碼。這里順便說一句,之所以這么取名,是因為 Java 字節碼指令的操作碼(opcode)被固定為一個字節。

      舉例來說,下圖的中間列,正是用 Java 寫的 Helloworld 程序編譯而成的字節碼。可以看到,它與 C 版本的編譯結果一樣,都是由一個個字節組成的。

      并且,我們同樣可以將其反匯編為人類可讀的代碼格式(如下圖的最右列所示)。不同的是,Java 版本的編譯結果相對精簡一些。這是因為 Java 虛擬機相對于物理機而言,抽象程度更高。

      # 最左列是偏移;中間列是給虛擬機讀的機器碼;最右列是給人讀的代碼
      0x00:  b2 00 02         getstatic java.lang.System.out
      0x03:  12 03            ldc "Hello, World!"
      0x05:  b6 00 04         invokevirtual java.io.PrintStream.println
      0x08:  b1               return

      Java 虛擬機可以由硬件實現 [1],但更為常見的是在各個現有平臺(如 Windows_x64、Linux_aarch64)上提供軟件實現。這么做的意義在于,一旦一個程序被轉換成 Java 字節碼,那么它便可以在不同平臺上的虛擬機實現里運行。這也就是我們經常說的“一次編寫,到處運行”。

      虛擬機的另外一個好處是它帶來了一個托管環境(Managed Runtime)。這個托管環境能夠代替我們處理一些代碼中冗長而且容易出錯的部分。其中最廣為人知的當屬自動內存管理與垃圾回收,這部分內容甚至催生了一波垃圾回收調優的業務。

      除此之外,托管環境還提供了諸如數組越界、動態類型、安全權限等等的動態檢測,使我們免于書寫這些無關業務邏輯的代碼。

      Java 虛擬機具體是怎樣運行 Java 字節碼的?

      下面我將以標準 JDK 中的 HotSpot 虛擬機為例,從虛擬機以及底層硬件兩個角度,給你講一講 Java 虛擬機具體是怎么運行 Java 字節碼的。

      從虛擬機視角來看,執行 Java 代碼首先需要將它編譯而成的 class 文件加載到 Java 虛擬機中。加載后的 Java 類會被存放于方法區(Method Area)中。實際運行時,虛擬機會執行方法區內的代碼。

      如果你熟悉 X86 的話,你會發現這和段式內存管理中的代碼段類似。而且,Java 虛擬機同樣也在內存中劃分出堆和棧來存儲運行時數據。

      不同的是,Java 虛擬機會將棧細分為面向 Java 方法的 Java 方法棧,面向本地方法(用 C++ 寫的 native 方法)的本地方法棧,以及存放各個線程執行位置的 PC 寄存器。

                                                              

       

      在運行過程中,每當調用進入一個 Java 方法,Java 虛擬機會在當前線程的 Java 方法棧中生成一個棧幀,用以存放局部變量以及字節碼的操作數。這個棧幀的大小是提前計算好的,而且 Java 虛擬機不要求棧幀在內存空間里連續分布。

      當退出當前執行的方法時,不管是正常返回還是異常返回,Java 虛擬機均會彈出當前線程的當前棧幀,并將之舍棄。

      從硬件視角來看,Java 字節碼無法直接執行。因此,Java 虛擬機需要將字節碼翻譯成機器碼。

      在 HotSpot 里面,上述翻譯過程有兩種形式:第一種是解釋執行,即逐條將字節碼翻譯成機器碼并執行;第二種是即時編譯(Just-In-Time compilation,JIT),即將一個方法中包含的所有字節碼編譯成機器碼后再執行。

       

                                                      

       

       

      前者的優勢在于無需等待編譯,而后者的優勢在于實際運行速度更快。HotSpot 默認采用混合模式,綜合了解釋執行和即時編譯兩者的優點。它會先解釋執行字節碼,而后將其中反復執行的熱點代碼,以方法為單位進行即時編譯。

      HotSpot 采用了多種技術來提升啟動性能以及峰值性能,剛剛提到的即時編譯便是其中最重要的技術之一。

      即時編譯建立在程序符合二八定律的假設上,也就是百分之二十的代碼占據了百分之八十的計算資源。

      對于占據大部分的不常用的代碼,我們無需耗費時間將其編譯成機器碼,而是采取解釋執行的方式運行;另一方面,對于僅占據小部分的熱點代碼,我們則可以將其編譯成機器碼,以達到理想的運行速度。

      理論上講,即時編譯后的 Java 程序的執行效率,是可能超過 C++ 程序的。這是因為與靜態編譯相比,即時編譯擁有程序的運行時信息,并且能夠根據這個信息做出相應的優化。

      舉個例子,我們知道虛方法是用來實現面向對象語言多態性的。對于一個虛方法調用,盡管它有很多個目標方法,但在實際運行過程中它可能只調用其中的一個。

      這個信息便可以被即時編譯器所利用,來規避虛方法調用的開銷,從而達到比靜態編譯的 C++ 程序更高的性能。

      為了滿足不同用戶場景的需要,HotSpot 內置了多個即時編譯器:C1、C2 和 Graal。Graal 是 Java 10 正式引入的實驗性即時編譯器,在專欄的第四部分我會詳細介紹,這里暫不做討論。

      之所以引入多個即時編譯器,是為了在編譯時間和生成代碼的執行效率之間進行取舍。C1 又叫做 Client 編譯器,面向的是對啟動性能有要求的客戶端 GUI 程序,采用的優化手段相對簡單,因此編譯時間較短。

      C2 又叫做 Server 編譯器,面向的是對峰值性能有要求的服務器端程序,采用的優化手段相對復雜,因此編譯時間較長,但同時生成代碼的執行效率較高。

      從 Java 7 開始,HotSpot 默認采用分層編譯的方式:熱點方法首先會被 C1 編譯,而后熱點方法中的熱點會進一步被 C2 編譯。

      為了不干擾應用的正常運行,HotSpot 的即時編譯是放在額外的編譯線程中進行的。HotSpot 會根據 CPU 的數量設置編譯線程的數目,并且按 1:2 的比例配置給 C1 及 C2 編譯器。

      在計算資源充足的情況下,字節碼的解釋執行和即時編譯可同時進行。編譯完成后的機器碼會在下次調用該方法時啟用,以替換原本的解釋執行。

      總結與實踐

      今天我簡單介紹了 Java 代碼為何在虛擬機中運行,以及如何在虛擬機中運行。

      之所以要在虛擬機中運行,是因為它提供了可移植性。一旦 Java 代碼被編譯為 Java 字節碼,便可以在不同平臺上的 Java 虛擬機實現上運行。此外,虛擬機還提供了一個代碼托管的環境,代替我們處理部分冗長而且容易出錯的事務,例如內存管理。

      Java 虛擬機將運行時內存區域劃分為五個部分,分別為方法區、堆、PC 寄存器、Java 方法棧和本地方法棧。Java 程序編譯而成的 class 文件,需要先加載至方法區中,方能在 Java 虛擬機中運行。

      為了提高運行效率,標準 JDK 中的 HotSpot 虛擬機采用的是一種混合執行的策略。

      它會解釋執行 Java 字節碼,然后會將其中反復執行的熱點代碼,以方法為單位進行即時編譯,翻譯成機器碼后直接運行在底層硬件之上。

      HotSpot 裝載了多個不同的即時編譯器,以便在編譯時間和生成代碼的執行效率之間做取舍。

       

      posted @ 2019-09-05 14:18  一支會記憶的筆  閱讀(1514)  評論(0)    收藏  舉報
      返回頂部
      【學無止境??謙卑而行】
      主站蜘蛛池模板: 亚洲av日韩av中文高清性色| 日韩人妻中文字幕精品| 国产国拍精品av在线观看| 成人国产精品一区二区网站公司| 国产99视频精品免费视频6| 国产精品大全中文字幕| 男人扒女人添高潮视频| 99久久国产成人免费网站| 精品日本免费一区二区三区| 免费网站看V片在线毛| 少妇粉嫩小泬喷水视频www| 五月综合激情婷婷六月| 欧美日韩在线亚洲二区综二| 九九九精品成人免费视频小说| 天堂亚洲免费视频| 成人小说亚洲一区二区三区| 澳门永久av免费网站| 久久精品国产久精国产| 激情亚洲专区一区二区三区| 亚洲欧洲一区二区福利片| 亚洲国产精品久久久久4婷婷 | 热久在线免费观看视频| 欧美黑人巨大xxxxx| 亚洲蜜桃av一区二区三区| 国产中文字幕精品免费| av无码精品一区二区乱子| 亚洲性线免费观看视频成熟| 洪湖市| 亚洲综合国产成人丁香五| 国产激情一区二区三区成人| 高清国产一区二区无遮挡| 免费无码AV一区二区波多野结衣| 成人欧美日韩一区二区三区| 亚洲精品97久久中文字幕无码| 国语精品自产拍在线观看网站| 亚洲成av人片天堂网无码| 国产线播放免费人成视频播放| 国产精品久久人妻无码网站一区 | 熟妇人妻久久春色视频网| 高潮videossex潮喷| 人成午夜免费大片|