1. 程式人生 > 其它 >Java虛擬機器結構——Java虛擬機器規範

Java虛擬機器結構——Java虛擬機器規範

前言

在文章中,經常能看到說著說著中文突然出來一段英文,這可能是因為這段的原理譯者也不太瞭解,所以不敢亂加翻譯,或者是這一段根本沒必要翻譯。

如果遇到這種格式的:

長段的英文句子

這應該是上面的一句話翻譯了,但是又怕和原文差之千里,所以貼上原文。

下面開始是原文了

===

原文:Chapter 2. The Structure of the Java Virtual Machine

這篇文件定義了一個抽象的Java虛擬機器,並不是某一個特定的Java虛擬機器實現。

要想正確的實現Java虛擬機器,你只需要能正確的讀取class檔案格式,執行定義在其中的操作即可。關於其實現細節,這並不是Java虛擬機器規範中的一部分,因為沒必要限制JVM實現者的創造力。例如,執行時資料區的記憶體佈局;Java垃圾收集器使用的演算法;任何JVM指令集的內部優化(比如它們轉譯成機器程式碼)的實現細節都沒有具體的限制,實現者具有自行決定如何實現的自由。

All references to Unicode in this specification are given with respect to The Unicode Standard, Version 13.0, available at https://www.unicode.org/.

class檔案格式

可以被Java虛擬機器執行的編譯後代碼錶現為一種獨立於硬體和作業系統的二進位制格式,通常(但並不必要)儲存在一個檔案中,稱為class檔案格式。class檔案格式精確的定義了類或介面的表示,including details such as byte ordering that might be taken for granted in a platform-specific object file format.

第四章、“類檔案格式”包含了class檔案的細節。

資料型別

和Java程式語言一樣,JVM提供了兩種型別:基本型別(primitive types)和引用型別(reference types)。相應的,有兩種型別的值可以被儲存在變數中、作為引數傳遞、被方法返回和操作,它們就是:基本值和引用值。

JVM期望在執行時,幾乎所有的型別檢查都已經完成,通常是通過一個編譯器或者是JVM自己(但不是必要的)來完成這種檢查。
基本型別的值並不需要在執行時被標記或是以其它方式被檢查,以確定它們的型別,或者是與引用型別的值所區分。相反,JVM的指令集使用與特定型別的值進行操作的指令來區分它們的運算元型別。比如:iadd

laddfaddddadd是JVM中將兩個數字相加並且產生一個數字結果的的所有指令,相應地,每一個指令都指定了它們的運算元型別:intlongfloatdouble。 For a summary of type support in the Java Virtual Machine instruction set, see §2.11.1.

JVM包含對物件的顯示支援。一個物件既可能是一個被動態分配的類的例項也可能是一個數組。 A reference to an object is considered to have Java Virtual Machine type reference.reference型別的值可以被想象成一個物件的指標。一個物件可能存在多個引用,物件總是通過一個reference型別的值被操作,傳遞和測試。

譯者:上面所說的reference型別的值,是JVM層面中的一種值,Java中並沒有這個說法。並且這裡說的基本型別、引用型別值都是JVM層面中的,並非Java層面中的,讀者需要以JVM的角度進行思考。

原始型別和值

JVM支援的基本型別有數字型別boolean型別和returnAddress型別。

數字型別包括整數型別浮點型別

整數型別包括:

  • byte,它的值為8位的有符號的二進位制補碼數(two's-complement),它的預設值是0
  • short,它的值為16位的有符號的二進位制補碼數(two's-complement),它的預設值是0
  • int,它的值為32位的有符號的二進位制補碼數(two's-complement),它的預設值是0
  • long,它的值為64位的有符號的二進位制補碼數(two's-complement),它的預設值是0
  • char,它的值為16位的無符號整數,表示Unicode code points in the Basic Multilingual Plane,被編碼為UTF-16,並且它們的預設值是null code point('\u0000')

浮點型別包括:

  • float,它的值精準的遵循了32位IEEE754 binary32格式的值表示,並且它的預設值是正0
  • double,它的值精準的遵循了64位IEEE754 binary64格式的值表示,並且它的預設值是正0

boolean型別的值將真假值編碼為truefalse,並且預設值是false

第一版的JVM規範沒有考慮將boolean作為一個JVM型別。However, boolean values do have limited support in the Java Virtual Machine. The Second Edition of The Java® Virtual Machine Specification clarified the issue by treating boolean as a type.

returnAddress型別的值是一個指向JVM指令集操作碼的指標。在所有基本型別中,只有returnAddress型別並不直接與Java程式語言中的型別相關。

整數型別和值

浮點型別和值

returnAddress型別和值

returnAddress型別被JVM中的jsrretjsr_w指令所使用,returnAddress型別的值是一個指向JVM指令集操作碼的指標。與數字基本型別不同,returnAddress並不與任何Java程式語言中的型別相關聯,並且不能被執行中的程式修改。

boolean型別

儘管JVM定義了一個boolean型別,但也僅僅只為它提供了一些非常有限的支援。JVM指令集中並沒有用來單獨對boolean值執行操作的指令,相反,Java程式語言中對boolean值進行操作的表示式被編譯為使用JVM中int資料型別的值。

JVM並不直接支援boolean陣列,newarray指令允許建立一個boolean陣列的。但一個boolean型別的陣列將被以byte陣列的指令(baloadbastore)被訪問和修改。

在Oracle的JVM實現中,Java程式語言中的boolean陣列將被編碼為JVM的byte陣列,每一個boolean元素使用8位。

JVM將boolean陣列中的元件使用1代表true和0代表false來編碼。Java程式語言中的boolean值將被編譯器對映成JVM中int型別的值,對此,編譯器必須使用相同的編碼。

引用型別和值

有三種引用型別:類型別,陣列型別和介面型別。相應的,它們的值分別是一個動態建立的類例項、陣列或一個實現了介面的類例項或陣列的引用。

一個數組型別具有一個單一維度的元件型別(它的長度並沒有由型別給出)。一個數組型別的元件型別本身也可能是一個數組型別。
如果從一個任意的陣列型別開始,考慮它的元件型別,然後(如果元件型別也是一個數組型別)考慮元件型別的元件型別,等等等等,最終必定會到達一個不是陣列型別的元件型別,這個型別稱作陣列型別的元素型別。一個數組的元素型別必須是基本型別、類型別或一個介面型別。

一個引用值也可能是特定的null引用,對於一個沒有引用到任何物件的引用,就通過null表示。
null引用初始情況下沒有執行時型別,但是可能轉換成任意的型別,引用型別的預設值是null

此規範並不強制將一個具體的值編碼為null。

This specification does not mandate a concrete value encoding null.

執行時資料區

JVM定義了多個在程式執行期間被使用的執行時資料區。其中的一些資料區跟隨JVM的生命週期,在JVM啟動時被建立,僅在JVM退出時被銷燬。其它的資料區跟隨執行緒的生命週期,執行緒資料區(Per-thread data areas)在一個執行緒被建立時建立並且在一個執行緒退出時被銷燬。

pc暫存器

JVM可以支援多個執行緒在同一時刻被執行。每一個JVM執行緒擁有它自己的pc(程式計數器)暫存器。在任一時刻,每一個JVM執行緒執行程式碼中的一個單一方法,該方法被稱作執行緒的當前方法。如果一個方法不是native的(不是本地方法),pc計數器就包含了當前正在執行的JVM指令的地址。如果當前執行緒執行的方法是native的,pc暫存器的值是未定義的。JVM的pc暫存器定義的足夠寬,以容納一個的returnAddress或一個特定平臺上的本地指標。

Java虛擬機器棧(Java Virtual Machine Stack)

每一個Java虛擬機器執行緒有它私有的Java虛擬機器棧,與執行緒在同一時刻被建立。一個Java虛擬機器棧中儲存著棧幀。一個Java虛擬機器棧類似於傳統程式語言(如C)中的棧,它儲存著本地變數和部分結果並且在方法呼叫和方法返回中扮演重要的部分(plays a part)。

it holds local variables and partial results, and plays a part in method invocation and return.

因為除了push和pop棧幀之外,Java虛擬機器棧從不會被直接操作,所以幀可以在堆中被分配。Java虛擬機器棧在記憶體中並不必須是連續的。

在第一版Java虛擬機器規範中,Java虛擬機器棧被稱作Java棧

這份定義允許Java虛擬機器棧具有固定大小或根據計算出的需求動態擴充套件和收縮。如果Java虛擬機器棧具有固定大小,那麼每一個Java虛擬機器棧的大小都可以在棧被建立時獨立的被選擇。

一個Java虛擬機器實現可能提供一個由程式設計師或使用者控制的初始Java虛擬機器棧大小,同樣,也可能在一個動態擴充套件和收縮的Java虛擬機器棧中控制最大和最小棧大小

下面的異常條件與Java虛擬機器棧相關

  1. 如果在一個執行緒中的計算需要一個比允許的Java虛擬機器棧大小更大的棧,JVM丟擲StackOverflowError
  2. 如果JVM棧可以被動態擴充套件,並且已經嘗試擴充套件但是並沒有足夠的記憶體可以完成這個擴充套件,或者沒有足夠的記憶體可以建立一個執行緒的初始Java虛擬機器棧,JVM丟擲OutOfMemoryError

堆(Heap)

Java虛擬機器有一個被所有JVM執行緒共享的(Heap)。堆是為所有類例項和陣列分配記憶體的執行時資料區。

堆在JVM啟動時被建立。堆中儲存的物件被自動儲存管理系統(俗稱垃圾回收器)回收,物件永遠不會被顯式的釋放。JVM沒有假設(它具有)特定的型別的自動儲存管理系統,可以根據實現者的系統需求來選擇合適的儲存管理技術。堆可能是固定大小的或者根據計算出的需要進行動態擴充套件收縮的。堆的記憶體並不需要是連續的。

一個JVM實現可以提供一個程式設計師或使用者控制的初始堆大小,與之類似,如果堆可以被動態擴充套件收縮,可以控制最大和最小堆大小

如下異常條件和堆相關:

  • 如果計算得知需要比自動記憶體管理系統可以獲得的更多的堆空間,JVM丟擲OutOfMemoryError

方法區(Method Area)

JVM具有一個在所有JVM執行緒間共享的方法區。方法就像一個傳統程式語言的編譯後代碼的儲存區域,或者像是作業系統程序中的文字段。它儲存每個類(pre-class)的結構,比如執行時常量池、域和方法資料,並且包括方法和構造器的程式碼,包括類或介面初始化和例項初始化時所使用的特殊方法。

方法區在JVM啟動時被建立,儘管方法區是堆的一個邏輯部分,但該區域的簡單實現可能選擇讓該區不被垃圾收集或壓縮。這份定義不強制要求方法區的位置或者管理編譯後代碼所使用的策略。方法區可以是固定大小或可以根據計算所得的需求被動態擴充套件和收縮的。方法區的記憶體並不需要是連續的。

一個JVM實現可以提供一個程式設計師或使用者控制的初始方法區大小,與之類似,如果方法區可以被動態擴充套件收縮,可以控制最大和最小方法區大小

如下的異常條件與方法區有關:

  • 如果方法區中的記憶體不能滿足分配請求,JVM丟擲OutOfMemoryError

執行時常量池(Run-time Constant Pool)

一個執行時常量池是每個類或介面的類檔案中的constant_pool表的執行時表示。它包含了多種型別的常量,範圍從編譯時可知的數字字面量到必須在執行時才能被解析的方法和域引用。執行時常量池提供一個提供了類似於傳統程式語言中符號表的功能,儘管它其中包含比典型的符號表更廣泛的資料。

每一個執行時常量池都在JVM的方法區中被分配,一個類或介面的執行時常量池在類或介面被JVM虛擬機器建立時被構造。

下面的異常條件與為一個類或介面構造執行時常量池有關:

  • 當建立一個類或介面時,如果執行時常量池需要比JVM方法區更多的記憶體空間,JVM丟擲OutOfMemoryError

See §5 (Loading, Linking, and Initializing) for information about the construction of the run-time constant pool.

本地方法棧(Native Method Stack)

Java虛擬機器的實現可以通過使用傳統的棧,通俗來講:“C棧”來支援本地方法。Java虛擬機器指令集直譯器的實現也可以使用本地方法棧,例如使用C實現(指令集直譯器)。
不能載入本地方法或者不依賴傳統棧的Java虛擬機器實現可以不提供本地方法棧,如果提供了,本地方法棧通常在每個執行緒建立時傳遞給對應執行緒。

這個定義允許本地方法棧是固定大小或者根據計算所需動態擴充套件或收縮,如果一個本地方法棧是固定大小的,那麼這個大小可以在每個執行緒建立時被獨立的選擇。

Java虛擬機器實現可以提供程式設計師或使用者控制的初始本地方法棧大小,同樣地,可變大小的本地方法棧可以控制最大和最小方法棧大小

下面的異常條件與本地方法棧相關:

  1. 如果計算出一個執行緒需要一個比允許值更大的本地方法棧,JVM丟擲StackOverflowError
  2. 如果本地方法棧可以被動態擴充套件並且已經嘗試了擴充套件但是並沒有足夠的記憶體用來擴充套件,或者在建立一個新執行緒時沒有足夠的記憶體來建立它的本地方法棧,JVM丟擲OutOfMemoryError

棧幀(Frame)

一個棧幀用於儲存資料和部分結果,以及執行動態連結,方法返回值和排程異常。

每當一個方法被呼叫,一個新的棧幀就被建立,每當一個方法呼叫完成,一個棧幀就被銷燬,不論時正常完成還是意外完成(丟擲一個未捕獲異常)。幀由每個執行緒的Java虛擬機器棧建立新幀時分配,每一個幀有一個自己的本地變數(local variable 又稱區域性變數)陣列,一個自己的運算元棧和一個類的當前方法在執行時常量池中的引用。

一個棧幀可以被擴展出附加的,特定於實現的(implementation-specific)資訊,比如除錯資訊(debugging information)

本地變數陣列和運算元棧的大小在編譯時被決定,並且與棧幀所關聯的方法的程式碼一起提供。因此棧幀資料結構的大小僅僅依賴JVM的實現,並且這些結構的記憶體會在方法呼叫時同步的被分配。

在給定執行緒的任何一個時刻只有一個棧幀——正在執行的方法的棧幀——是活躍的。這個棧幀被認為是當前棧幀,並且這個方法被認為是當前方法。當前方法被定義的類稱作當前類。本地變數和運算元棧的操作通常引用當前棧幀。

Operations on local variables and the operand stack are typically with reference to the current frame.

當一個方法呼叫了另一個方法或者方法完成時,這個方法的棧幀不再是當前棧幀。當一個方法被呼叫,一個新的棧幀被建立並且當控制權轉移到這個新方法時,該棧幀變成當前棧幀。在方法返回時,當前棧幀回傳它的方法呼叫的結果給上一個棧幀(如果有的話)。然後當前棧幀將被丟棄,因為前一個棧幀變成了當前棧幀。

注意一個執行緒建立的棧幀是那個執行緒私有的,並且不能被任何其它執行緒所訪問。

本地變數(Local Variables)

每一個棧幀包含一個儲存本地變數的陣列,這個陣列的長度在編譯時被確定並且由一個二進位制形式的類或介面中該棧幀關聯的方法所提供。

一個單獨的本地變數可以儲存一個booleanbytecharshortintfloatreferencereturnAddress型別的值,longdouble型別的值需要由一對兒變數儲存。

本地變數通過索引被找到,第一個本地變數的索引是0。當且僅當一個整數比本地變數陣列的大小小0和1時,這個整數才被認為是本地變數陣列的索引。

An integer is considered to be an index into the local variable array if and only if that integer is between zero and one less than the size of the local variable array.

一個longdouble型別的值佔據兩個連續的本地變數,這樣的值通過較小的那個索引來找到。比如一個double值儲存在本地變數陣列中索引為n的位置,那麼實際上它佔據了nn+1。這種情況下,不能從索引n+1處載入變數,但是可以向其中儲存,儘管這樣做會讓區域性變數n的內容失效。

JVM不需要n是偶數。直觀地說,longdouble不需要再本地變數陣列中64位對齊。實現者可以自由的決定合適的方法來使用兩個區域性變數來表示這種值。

Implementors are free to decide the appropriate way to represent such values using the two local variables reserved for the value.

JVM使用本地變數來接收方法呼叫的引數。在類方法呼叫中,任何引數傳遞進去的引數都從本地變數0開始被連續的儲存在本地變數中。在例項方法呼叫中,本地變數0總是被用於傳遞方法被呼叫的例項的物件(在Java程式語言中的this)。任何引數隨後從區域性變數1開始的連續區域性變數中傳遞。

運算元棧

每一個棧幀包含一個後進先出(LIFO)棧,稱為運算元棧。運算元棧的最大深度在編譯時被決定並且由關聯到棧幀的方法中的程式碼提供。

在上下文明確的情況下,我們有時會把當前棧幀的運算元棧稱為運算元棧(省略當前棧幀幾個字)。

當包含它的棧幀被建立時,運算元棧是空的。JVM提供了從本地變數或域中載入常量或值到運算元棧中的指令。其它JVM指令從運算元棧中拿出運算元,運算它們,然後將結果重新放入運算元棧中。運算元棧也被用於準備傳入方法的引數和接收方法的返回值。

例如,iadd指令將兩個int值相加。它要求要進行加法的兩個int值是運算元棧頂的兩個值,這兩個值由之前的指令push到運算元棧中。這兩個int值都被從運算元棧中彈出,它們相加了,並且它們的和被壓回運算元棧頂。子計算可以巢狀在運算元棧上,從而產生可由包含計算使用的值(這裡我猜說的是帶括號的計算這種形式)

Subcomputations may be nested on the operand stack, resulting in values that can be used by the encompassing computation.

運算元棧的每一個條目都可以儲存任意JVM型別的值,包括longdouble

運算元棧中的值必須以適合它們型別的方式進行操作。比如,下面兩種操作是不可能的:壓入兩個int值然後將它們看作long或者壓入兩個float然後使用iadd將它們相加。一小部分JVM指令(dupswap指令)像操作原始值一樣操作執行時資料區,而不關心它們特定的型別。這些指令被以一種不能夠修改或破壞獨立的值的方式被定義。這些對運算元棧操作的限制是在class檔案校驗階段被強制執行的。

在任一時間,一個運算元棧都有一個關聯的深度,longdouble佔用兩個單元的深度,其它值佔用一個單元的深度。

動態連結

為了支援方法程式碼的動態連結,每一個棧幀包含一個當前方法的型別在執行時常量池中的引用。方法的類檔案程式碼會通過符號引用(symbolic references)來引用要呼叫的方法和訪問的變數。動態連結將這些符號方法引用翻譯成實際的方法引用,在必要的時候執行類載入以解析尚未定義的符號,並且將變數訪問翻譯成與這些變數執行時位置相關的儲存結構中對應的偏移量。

這個方法和變數的延遲繫結(late binding)會使方法中使用的其他類中的更改不太可能破壞方法的程式碼。

方法呼叫正常結束

如果一個呼叫沒有引起一個被丟擲的異常,不管是JVM直接丟擲的還是由於作為執行一個特定的throw語句所產生的結果,該方法的結束都是正常結束。如果當前方法的呼叫正常結束,一個值將被返回給呼叫者方法(invoking method)。當被呼叫方法執行了任何一個返回指令時就會發生這種情況,返回指令的選擇必須和返回的值的型別相對應(如果有的話)。

這個示例中的當前棧幀被用來恢復呼叫者的狀態,包括它的本地變數和運算元棧,並適當增加呼叫者的程式計數器以跳過本次方法呼叫指令。
然後,呼叫者方法就在它的棧幀中繼續正常執行,之前方法的返回值被壓到呼叫者方法的運算元棧中。

方法呼叫意外結束

如果一個方法中的JVM指令的執行導致了一個JVM丟擲了一個異常,並且這個異常沒有被method處理,這個方法呼叫就是意外結束的。執行一個athrow指令也會導致一個一場被顯式的丟擲並且如果異常沒被當前方法捕獲,結果就是方法呼叫異常結束。一個異常結束的方法呼叫永遠不會返回一個值給它的呼叫者。

物件表示

JVM不強制任何特定的物件內部結構。

在一些Oracle的JVM實現中,一個類的例項的引用是一個控制代碼的指標,而控制代碼本身就是一對指標:一個指向一個包含物件的方法的表和一個指向代表物件型別的Class物件的指標,另一個指向物件資料在堆中被分配的記憶體

In some of Oracle’s implementations of the Java Virtual Machine, a reference to a class instance is a pointer to a handle that is itself a pair of pointers: one to a table containing the methods of the object and a pointer to the Class object that represents the type of the object, and the other to the memory allocated from the heap for the object data.

浮點數演算法

特殊方法

例項初始化方法

一個類具有0個或者多個例項初始化方法,每一個通常對應著一個通過Java程式語言編寫的構造器。

一個滿足下面所有條件的方法就是一個例項初始化方法:

  1. 定義在一個類中(非介面中)
  2. 具有特殊的名字<init>
  3. 它是void

在一個類中,一個叫<init>的非void方法不是一個例項初始化方法,在一個介面中,任何叫<init>的方法都不是一個例項初始化方法。這些方法並不能被JVM虛擬機器指令呼叫並且會在格式檢查中被拒絕。

例項初始化方法的定義和使用被JVM所限制。在定義中,方法的access_flags專案和code陣列受限。而在使用中,一個例項初始化方法將僅能被invokespecial指令在一個未初始化類的例項上呼叫。

因為名稱<init>並不是一個Java程式語言中合法的識別符號,所以它並不能直接被Java程式語言編寫的程式所使用

類初始化方法

一個類或者介面具有最多一個類或介面的初始化方法,並且它們(類和介面)被JVM通過呼叫這個方法來初始化。

如果一個方法滿足下面的所有定義,那麼它是一個類或介面的初始化方法:

  1. 它具有特殊的名字<clinit>
  2. 它是void
  3. 在一個版本號在51.0(JAVA7)或更高的類檔案中,方法的ACC_STATIC標誌被設定並且沒有引數

ACC_STATIC的要求在Java SE 7中被引入,不接受引數在Java SE 9中。在一個版本號在50.0及以下的類檔案中,一個名字叫<clinit>,返回void的方法就可以被認為是類或介面的初始化方法,不論ACC_STATIC是否設定或是它們是否接收引數

類檔案中其它叫<clinit>的方法不是類或介面的初始化方法。它們永遠不會被JVM本身呼叫,不能被任何JVM指令呼叫,並且會被格式檢查所拒絕。

因為名字<clinit>並不是一個合法的Java程式語言識別符號,所以它不能直接在一個使用Java程式語言編寫的程式中被使用

簽名多型方法(Signature Polymorphic Methods)

譯者:下面的內容和Java7開始新增的動態方法呼叫和Java9中出現的變數控制代碼有關,如果從未學習過相關的知識,不妨跳過這一段。

一個滿足下面所有條件的方法是簽名多型方法

  1. 被宣告在java.lang.invoke.MethodHandle類或java.lang.invoke.VarHandle類中
  2. 具有單個形式的Object[]型別引數
  3. 具有ACC_VARARGSACC_NATIVE標誌

Java虛擬在invokevirtual指令中給簽名多型方法做了一些特殊處理,為了影響一個method handle(方法控制代碼)的呼叫或者影響一個被java.lang.invoke.VarHandle的例項所引用的變數。

一個方法控制代碼是一個對底層方法、構造器和域或者類似的低階操作的動態強型別且直接可執行的一個引用,具有可選的引數和返回值的轉換。一個java.lang.invoke.VarHandle的例項是一個變數或一個變數簇的動態強型別的引用,包括static域、非static域、陣列元素或一個堆外資料結構的元件。檢視Java SE平臺API中的java.lang.invoke包來了解更多資訊。

異常

一個JVM中的異常被表示為一個Throwable或它的任何子類的例項。丟擲一個異常會導致從丟擲異常的位置立即進行非本地的控制轉移。

Throwing an exception results in an immediate nonlocal transfer of control from the point where the exception was thrown.

大多數異常是由於一個發生異常的執行緒的操作而同步發生的。相對的,一個非同步異常可以在一個程式執行的任何時間點發生。JVM丟擲異常有如下三種原因:

  • 一個athrow指令被執行
  • 一個反常的執行條件被JVM同步的檢測到。這些異常不會在程式中的任意位置丟擲,而是在一個指令的執行後同步丟擲的:
    • 特定型別的異常:
      • 當指令體現了一個違反Java程式語言語義的一個操作時。比如索引一個數組的界限之外。
      • 在一個程式的載入或連結部分發生了一個錯誤
    • 導致一些資源達到最大限制,比如使用了太多記憶體
  • 一個非同步異常被丟擲因為:
    • ThreadThreadGroup類的stop方法被呼叫或者
    • 一個JVM實現的內部錯誤發生
      stop方法可能一個執行緒呼叫去影響另一個執行緒或者在一個特定執行緒組的所有執行緒。它們是非同步的因為它們可能在其它執行緒(thread and threads)執行的任意點發生。一個內部錯誤也被認為是非同步的。

一個Java虛擬機器可以允許一個少量但有限的執行在非同步異常被丟擲之前發生。這個延時允許優化的程式碼在符合Java程式語言語義的情況下檢測並丟擲這些異常。

未完...

指令集總結

類庫

未完...

公有設計,私有實現

未完...