JVM-位元組碼指令

来源:http://www.cnblogs.com/lrh-xl/archive/2016/04/04/5351453.html
-Advertisement-
Play Games

Java虛擬機位元組碼指令 瞭解了class文件,我覺得就很有必要去瞭解一下JVM中的位元組碼指令,那樣堆class文件以及JVM運行機制也後很大的幫助. Java虛擬機的指令由一個位元組長度的,代表著某種特定操作含義的數字(稱為操作碼,Opcode)以及跟隨其後的零至多個代表所需參數(稱為操作數,Opr ...


Java虛擬機位元組碼指令

  瞭解了class文件,我覺得就很有必要去瞭解一下JVM中的位元組碼指令,那樣堆class文件以及JVM運行機制也後很大的幫助. 

  Java虛擬機的指令由一個位元組長度的,代表著某種特定操作含義的數字(稱為操作碼,Opcode)以及跟隨其後的零至多個代表所需參數(稱為操作數,Oprands)而構成.由於Java虛擬機採用面向操作數棧而不是寄存器的架構,所以大多參數的指令都不包含操作數,只有一個操作碼.

位元組碼指令的一些特性

  由於限制了Java虛擬機操作碼的長度為一個位元組(0~255),這意味著指令集的操作碼總數不可能超過256條.

  由於class文件格式放棄了編譯後的操作數長度對齊,這意味著虛擬機處理那些超過一個位元組數據的時候,不得不在運行時從位元組中重建出具體數據的結構.如果要將一個16位長度的無符號整數,使用兩個無符號位元組存儲起來(將它們命名為byte1和byte2),那它們的值應該是這樣的:(byte<<8)| byte2 .這種操作在某種程度上會導致解釋執行位元組碼的時候會損失一些性能.但這樣做的優勢也是非常明顯的,放棄了操作數長度對齊,就意味著可以省略很多填充和間隔符號:用一個位元組來表示操作碼,也是為了儘可能獲得短小精幹的編譯代碼.

 位元組碼指令與數據類型

  對於大部分與數據類型相關的位元組碼指令它們的操作碼助記符中都有特殊特的字元來表明專門為哪種數據類型服務:i:代表int,l代表long,s代表short,b代表byte,c代表char,f代表float,d代表double,a代表reference.

  Java虛擬機的指令集對於特定的操作只提供了有限的類型相關指令去支持它,換句話說,指令集將會故意被設計成非完全獨立的Java虛擬機規範中把這種特性稱為"Not Orthpogoal".即並非每種操作都有對應的指令.有一些單獨的指令可以在必要的時候來將一些不支持的類型轉換成為可被支持的類型.

 載入和存儲指令

  載入和存儲指令用於將數據在棧幀中的局部變數和操作數之間來回傳輸.

  將一個局部變數載入到操作棧:ilaod , ioload<n>,llaod , llaod<n>,float,float<n>,double,double<n>,aload,aload<n>.

  將一個數據從操作數棧存儲到局部變數表:istore,istore<n>,lstore,lstore<n>,fstore.fstore<n>,dstore,dstore<n>,astore,asotre<n>.

  將一個常量載入到數據棧:bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_<i>,lconst_<l>,fconst_<f>,dconst_<d>

  擴充局部變數表訪問索引的指令:wide

 運算指令

  運算或算術指令用於對兩個操作數棧上的值進行某種特定運算,並把結果重新存入到操作棧頂.

  大體上算術指令可以分為兩種:對整型數據進行運算的指令對浮點數據進行運算的指令.無論是哪種算術指令,都使用Java虛擬機的數據類型,由於沒有直接支持byte,short,char和boolean類型的算術指令,對於這類數據的運算應使用操作int類型的指令代替.

  加法指令:iadd,ladd,fadd,dadd

  減法指令:isub,lsub,fsub,dsub

  乘法指令:imul,lmul,fmul,dmul

  求餘指令:irem,lrem,frem,drem

  求反指令:ineg,lneg,fneg,dneg

  移位指令:ishl.ishr,lshl,lshr,lushr

  按位或指令:ior,lor

  按位與指令:iand,land]

  按位異或指令:ixor,lxor

  局部變數自增指令:iinc

  比較指令:dcmpy,dcmpl,fcmpg,fsmpyl,lcomp

  Java虛擬機要求在進行浮點數運算時,所有的運算結果都必須舍入到適當的精度,非精確的結果必須舍入為可被表示的最接近的精確值.如果有兩種可表示的形式與該值一樣接近,將優先選擇最低有效位為零的,稱為向最近數舍入模式.

  在把浮點數轉換為整數時,Java虛擬機使用IEEE754規範中的向零舍入模式,這中模式的舍入結果會導致數字被截斷,所有小數部分的有效位元組都會被丟棄掉.向零舍入模式將在目標數值類型與該數值類型中選擇一個最接近但是不大於原數值的數字來作為最精確的舍入結果.

  Java虛擬機在處理浮點數運算時,不會拋出任何運行時異常,當一個操作產生溢出時,將會使用有符號的無窮大來表示,如果某個操作結果沒有明確的數學定義的話,將會使用NaN值來表示,所有使用NaN值作為操作數的算術運算,結果都會返回NaN.

  在對long類型數值進行比較時,虛擬機採用帶符號的比較方式,而對浮點數值,進行比較時(dcmpy,dcmpl,fcmpg,fcmpl),虛擬機會採用IEEE754規範所定義的無信號比較(Nonsignaling Conparions)方式.  

 

類型轉換指令

  類型轉換指令可以將兩種不同的數值類型進行相互轉換

  Java直接支持(即轉換時無需顯示進行轉換指令)以下數值類型的寬化類型轉化(即範圍類型向大範圍類型的安全轉化):

  1. int  -->long , float , double
  2. long -->float , double
  3. float -->double

  處理窄化類型轉換時,必須顯示的使用轉換指令來完成,這些轉換指令包括:i2b , i2c , i2s , l2i , f2c , d2i , d2l , d2f.窄化類型轉換可能會導致轉換結果產生不同的正負號,不同的數量級的情況,轉換可能會導致數值精度丟失.

  將一個浮點型數值窄化為整型類型(int 或long)的時候,將遵循一下轉換規則

  • 如果浮點值是NaN,那轉換結果就是int或long類型的0.
  • 如果浮點值不是無窮大的話,浮點值使用向零舍入模式取整,獲得整數v.如果v在目標類型的表示範圍之內,轉換結果就是v.
  • 否則,將根據v的符號,轉換為一個T所能表示的最大會最小正數.

對象創建與訪問指令

  指令:

  • 創建類實例的指令:new
  • 創建數組得到指令:newarray , anewarray , multianewarray
  • 訪問類欄位(static 欄位,或者稱為類變數)和實例欄位(非static 欄位,或者稱為實例變數)的指令:getfield , putfield , getstatic , putstatic\
  • 把一個數組元素載入到操作數棧的指令:baload , caload , saload , iaload , laload , faload , daload , aaload
  • 將一個操作數棧的值存儲到數組元素中的指令:bastore , castore , sastore , iastore , fastore , dastore , aastore
  • 取數組長度的指令:arraylength
  • 檢查類實例類型的指令:instanceof , checkcast

 操作數棧管理指令

  Java虛擬機提供了一些直接操作操作數的指令:

  • 操作數棧的棧頂一個或兩個元素出棧:pop , po2
  • 複製棧頂一個或兩個元素並將複製值或雙份值重新壓入棧頂:dup ,dup2,duo_x1,dup_x2,dup2_x2
  • 將棧最頂端的兩個數值交換:swap

 控制轉移指令

  控制轉移指令可以讓Java虛擬機有條件的從指定的位置而不是控制轉移指令的下一條指令繼續執行程式。可以認為控制轉移指令就是在有條件或無條件的修改PC寄存器的值。

  控制轉移指令:

  • 條件分支:ifeq,iflt,ifne,ifge,ifgt,ifnull,ifnonnull,if_icmpeq,if_icmpne,if_icmplt,if_cmpgt,if_icmpge,if_cmpge,if_icmpeq,if_acmpne
  • 複合條件分支:tableswitch,lookupswitch
  • 無條件分支:goto,goto_w,jsr,jsr_w,ret

 方法調用和返回指令

  invokevirtual指令用於調用對象德邦實例方法,根據對象的實體的類型進行分派(虛方法分派),也就是Java語言中最常見的方法分派方式。

  invokeinterface指令用於調用介面方法,它會在運行時搜索一個實現了這個介面方法的對象找出適合的方法進行調用。

  invokespecial指令用於調用一些需要特殊處理的實例方法,包括實例初始化方法,私有方法和父類方法

  involvestatic指令用於調用類的方法(static方法)

  invokedynamic指令用於在運行時動態解析出調用點限定符所引用的方法,並執行該方法

  前面4條調用指令的分派邏輯都固化在Java虛擬機的內部,而invokedynamic指令的分派邏輯是由用戶設定的引導方法決定的 

 

異常處理指令 

  在Java虛擬機中處理異常catch語句不是由位元組碼指令來實現的,而是用異常表來完成的。

  在Java程式中顯式拋出異常的操作(throw語句)都是由athrow來實現的,除了用throw語句顯式拋出異常的情況之外,Java虛擬機規範還規定了許多運行時異常會在其他Java虛擬機指令檢測到異常狀況時自動拋出。

 同步指令

  Java虛擬機可以支持方法級的同步和方法內部一段指令序列的同步。這兩種同步結構都是使用管理(Monitor)來支持的。

  方法級的同步是隱含的,既無需通過位元組碼指令來控制,也實現在方法調用和返回操作之中。

  同步一段指令序列通常是由Java語言中的synchronize語句塊來表示的,Java虛擬機的指令集中有monitorenter和monitorexit兩條指令來支持synchronize關鍵字的語義,正確實現synchronized關鍵字需要Java編譯器與Java虛擬機兩者共同協作支持


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天突然看到一篇文章,講異常機制的實現,所以分享一下:http://baiy.cn/doc/cpp/inside_exception.htm 內容講的很深,但是編譯器的實現是不是真是這樣就不知道了,我也沒驗證過,事實上是要是仔細觀察彙編碼和棧則真有可能能驗證一下。但是憑我的能力不一定能完全驗證出來, ...
  • 續言 對於本次更新,我想說: 本框架由本人挑時間完善,而我還不是PHP大神級的人物,所以框架漏洞難免,求大神們指出。 本框架的知識點應用都會寫在博客里,大家有什麼異議的可以一起討論,也希望看博客的也能學習到它們。 本次更新,更新了函數規範上的一些問題,如將函數儘量的獨立化,每一個函數儘量只單獨做好一 ...
  • 今天有在校學生問怎麼獲取類中的成員變數的地址偏移量,這個應該是很多初學C++的人很好奇的問題。以前我在學校的時候,也有過這種需求。忘了當時是要寫什麼“奇怪的程式”了,反正需要獲取一個類的成員變數的地址偏移量。 其實這個問題很簡單,如果你瞭解C++的類對象記憶體分佈的話,這個根本不是問題。我給他舉了個例 ...
  • 一般來說傳圖片可以以流的形式來傳輸,即便是用json傳輸,一般也都是傳一個地址,而圖片都存在伺服器上,然後順著地址發送請求下載圖片。 但是這次公司的項目中,圖片是存在oracle資料庫中的blob欄位的,並沒有存在伺服器上,也就是說我必須傳圖片本身過去,而json是無法傳輸二進位的文本格式,因此我就 ...
  • 官方定義: Swoole:重新定義PHP PHP的非同步、並行、高性能網路通信引擎,使用純C語言編寫,提供了PHP語言的非同步多線程伺服器,非同步TCP/UDP網路客戶端,非同步MySQL,非同步Redis,資料庫連接池,AsyncTask,消息隊列,毫秒定時器,非同步文件讀寫,非同步DNS查詢。 Swoole內 ...
  • 1.org.apache.catalina.servlets.DefaultServlet 首先所有的請求進入tomcat,都會流經servlet,如果沒有匹配到任何應用指定的servlet,那麼就會流到預設的servlet。預設的servlet是配置在/conf/web.xml裡面的。配置文件中被 ...
  • Activiti的設計編輯器功能 Create Activiti projects and diagrams. 創建Activiti的項目和圖表。 The Activiti Designer creates a .bpmn file when creating a new Activiti diag ...
  • 前一篇已經翻譯過termvectors的使用方法了,這對於學習如何使用tf idf來說是很有幫助的了。 更多內容參考 "我整理的ELK教程" 什麼是TF IDF? 今天早晨起來,看《ES IN ACTION》的時候,遇到了這個術語,看英文實在不明白,於是百度了一下。看到了阮一峰的一篇關於它的文章,講 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...