<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 30,  comments - 85,  trackbacks - 0

     

    一、什么是Java虛擬機(jī)
         當(dāng)你談到Java虛擬機(jī)時(shí),你可能是指:
         1、抽象的Java虛擬機(jī)規(guī)范
         2、一個(gè)具體的Java虛擬機(jī)實(shí)現(xiàn)
         3、一個(gè)運(yùn)行的Java虛擬機(jī)實(shí)例
    二、Java虛擬機(jī)的生命周期
         一個(gè)運(yùn)行中的Java虛擬機(jī)有著一個(gè)清晰的任務(wù):執(zhí)行Java程序。程序開始執(zhí)行時(shí)他才運(yùn)行,程序結(jié)束時(shí)他就停止。你在同一臺(tái)機(jī)器上運(yùn)行三個(gè)程序,就會(huì)有三個(gè)運(yùn)行中的Java虛擬機(jī)。
         Java虛擬機(jī)總是開始于一個(gè)main()方法,這個(gè)方法必須是公有、返回void、直接受一個(gè)字符串?dāng)?shù)組。在程序執(zhí)行時(shí),你必須給Java虛擬機(jī)指明這個(gè)包換main()方法的類名。
         Main()方法是程序的起點(diǎn),他被執(zhí)行的線程初始化為程序的初始線程。程序中其他的線程都由他來啟動(dòng)。Java中的線程分為兩種:守護(hù)線程 daemon)和普通線程(non-daemon)。守護(hù)線程是Java虛擬機(jī)自己使用的線程,比如負(fù)責(zé)垃圾收集的線程就是一個(gè)守護(hù)線程。當(dāng)然,你也可 以把自己的程序設(shè)置為守護(hù)線程。包含Main()方法的初始線程不是守護(hù)線程。
         只要Java虛擬機(jī)中還有普通的線程在執(zhí)行,Java虛擬機(jī)就不會(huì)停止。如果有足夠的權(quán)限,你可以調(diào)用exit()方法終止程序。
    三、Java虛擬機(jī)的體系結(jié)構(gòu)
         Java虛擬機(jī)的規(guī)范中定義了一系列的子系統(tǒng)、內(nèi)存區(qū)域、數(shù)據(jù)類型和使用指南。這些組件構(gòu)成了Java虛擬機(jī)的內(nèi)部結(jié)構(gòu),他們不僅僅為Java虛擬機(jī)的實(shí)現(xiàn)提供了清晰的內(nèi)部結(jié)構(gòu),更是嚴(yán)格規(guī)定了Java虛擬機(jī)實(shí)現(xiàn)的外部行為。 
         每一個(gè)Java虛擬機(jī)都由一個(gè)類加載器子系統(tǒng)(class loader subsystem),負(fù)責(zé)加載程序中的類型(類和接口),并賦予唯一的名字。每一個(gè)Java虛擬機(jī)都有一個(gè)執(zhí)行引擎(execution engine)負(fù)責(zé)執(zhí)行被加載類中包含的指令。
         程序的執(zhí)行需要一定的內(nèi)存空間,如字節(jié)碼、被加載類的其他額外信息、程序中的對(duì)象、方法的參數(shù)、返回值、本地變量、處理的中間變量等等。Java虛擬機(jī)將 這些信息統(tǒng)統(tǒng)保存在數(shù)據(jù)區(qū)(data areas)中。雖然每個(gè)Java虛擬機(jī)的實(shí)現(xiàn)中都包含數(shù)據(jù)區(qū),但是Java虛擬機(jī)規(guī)范對(duì)數(shù)據(jù)區(qū)的規(guī)定卻非常的抽象。許多結(jié)構(gòu)上的細(xì)節(jié)部分都留給了 Java虛擬機(jī)實(shí)現(xiàn)者自己發(fā)揮。不同Java虛擬機(jī)實(shí)現(xiàn)上的內(nèi)存結(jié)構(gòu)千差萬別。一部分實(shí)現(xiàn)可能占用很多內(nèi)存,而其他以下可能只占用很少的內(nèi)存;一些實(shí)現(xiàn)可 能會(huì)使用虛擬內(nèi)存,而其他的則不使用。這種比較精煉的Java虛擬機(jī)內(nèi)存規(guī)約,可以使得Java虛擬機(jī)可以在廣泛的平臺(tái)上被實(shí)現(xiàn)。
         數(shù)據(jù)區(qū)中的一部分是整個(gè)程序共有,其他部分被單獨(dú)的線程控制。每一個(gè)Java虛擬機(jī)都包含方法區(qū)(method area)和堆(heap),他們都被整個(gè)程序共享。Java虛擬機(jī)加載并解析一個(gè)類以后,將從類文件中解析出來的信息保存與方法區(qū)中。程序執(zhí)行時(shí)創(chuàng)建的 對(duì)象都保存在堆中。 
         當(dāng)一個(gè)線程被創(chuàng)建時(shí),會(huì)被分配只屬于他自己的PC寄存器“pc register”(程序計(jì)數(shù)器)和Java堆棧(Java stack)。當(dāng)線程不掉用本地方法時(shí),PC寄存器中保存線程執(zhí)行的下一條指令。Java堆棧保存了一個(gè)線程調(diào)用方法時(shí)的狀態(tài),包括本地變量、調(diào)用方法的 參數(shù)、返回值、處理的中間變量。調(diào)用本地方法時(shí)的狀態(tài)保存在本地方法堆棧中(native method stacks),可能再寄存器或者其他非平臺(tái)獨(dú)立的內(nèi)存中。
         Java堆棧有堆棧塊(stack frames (or frames))組成。堆棧塊包含Java方法調(diào)用的狀態(tài)。當(dāng)一個(gè)線程調(diào)用一個(gè)方法時(shí),Java虛擬機(jī)會(huì)將一個(gè)新的塊壓到Java堆棧中,當(dāng)這個(gè)方法運(yùn)行結(jié)束時(shí),Java虛擬機(jī)會(huì)將對(duì)應(yīng)的塊彈出并拋棄。
         Java虛擬機(jī)不使用寄存器保存計(jì)算的中間結(jié)果,而是用Java堆棧在存放中間結(jié)果。這是的Java虛擬機(jī)的指令更緊湊,也更容易在一個(gè)沒有寄存器的設(shè)備上實(shí)現(xiàn)Java虛擬機(jī)。 
         圖中的Java堆棧中向下增長的,PC寄存器中線程三為灰色,是因?yàn)樗趫?zhí)行本地方法,他的下一條執(zhí)行指令不保存在PC寄存器中。
    四、數(shù)據(jù)類型(Data Types
         所有Java虛擬機(jī)中使用的數(shù)據(jù)都有確定的數(shù)據(jù)類型,數(shù)據(jù)類型和操作都在Java虛擬機(jī)規(guī)范中嚴(yán)格定義。Java中的數(shù)據(jù)類型分為原始數(shù)據(jù)類型 primitive types)和引用數(shù)據(jù)類型(reference type)。引用類型依賴于實(shí)際的對(duì)象,但不是對(duì)象本身。原始數(shù)據(jù)類型不依賴于任何東西,他們就是本身表示的數(shù)據(jù)。
    所有Java程序語言中的原始 數(shù)據(jù)類型,都是Java虛擬機(jī)的原始數(shù)據(jù)類型,除了布爾型(boolean)。當(dāng)編譯器將Java源代碼編譯為自己碼時(shí),使用整型(int)或者字節(jié)型 byte)去表示布爾型。在Java虛擬機(jī)中使用整數(shù)0表示布爾型的false,使用非零整數(shù)表示布爾型的true,布爾數(shù)組被表示為字節(jié)數(shù)組,雖然他 們可能會(huì)以字節(jié)數(shù)組或者字節(jié)塊(bit fields)保存在堆中。
         除了布爾型,其他Java語言中的原始類型都是Java虛擬機(jī)中的數(shù)據(jù)類型。在Java中數(shù)據(jù)類型被分為:整形的byteshortintlongchar和浮點(diǎn)型的floatdoubleJava語言中的數(shù)據(jù)類型在任何主機(jī)上都有同樣的范圍。 
         Java虛擬機(jī)中還存在一個(gè)Java語言中不能使用的原始數(shù)據(jù)類型返回值類型(returnValue)。這種類型被用來實(shí)現(xiàn)Java程序中的“finally clauses”,具體的參見18章的“Finally Clauses”
         引用類型可能被創(chuàng)建為:類類型(class type),接口類型(interface type),數(shù)組類型(array type)。他們都引用被動(dòng)態(tài)創(chuàng)建的對(duì)象。當(dāng)引用類型引用null時(shí),說明沒有引用任何對(duì)象。
         Java虛擬機(jī)規(guī)范只定義了每一種數(shù)據(jù)類型表示的范圍,沒有定義在存儲(chǔ)時(shí)每種類型占用的空間。他們?nèi)绾?/span>存儲(chǔ)Java虛擬機(jī)的實(shí)現(xiàn)者自己決定。關(guān)于浮點(diǎn)型更多信息參見14“Floating Point Arithmetic”

    TypeRange
    byte8-bit signed two's complement integer (-27 to 27 - 1, inclusive)
    short16-bit signed two's complement integer (-215 to 215 - 1, inclusive)
    int32-bit signed two's complement integer (-231 to 231 - 1, inclusive)
    long64-bit signed two's complement integer (-263 to 263 - 1, inclusive)
    char16-bit unsigned Unicode character (0 to 216 - 1, inclusive)
    float32-bit IEEE 754 single-precision float
    double64-bit IEEE 754 double-precision float
    returnValueaddress of an opcode within the same method
    referencereference to an object on the heap, or null

    五、字節(jié)長度
         Java虛擬機(jī)中最小的數(shù)據(jù)單元式字(word),其大小由Java虛擬機(jī)的實(shí)現(xiàn)者定義。但是一個(gè)字的大小必須足夠容納byteshortint charfloatreturnValuereference;兩個(gè)字必須足夠容納longdouble。所以虛擬機(jī)的實(shí)現(xiàn)者至少提供的字不能小 31bits的字,但是最好選擇特定平臺(tái)上最有效率的字長。
         在運(yùn)行時(shí),Java程序不能決定所運(yùn)行機(jī)器的字長。字長也不會(huì)影響程序的行為,他只是在Java虛擬機(jī)中的一種表現(xiàn)方式。
    六、類加載器子系統(tǒng)
         Java虛擬機(jī)中的類加載器分為兩種:原始類加載器(primordial class loader)和類加載器對(duì)象(class loader objects)。原始類加載器是Java虛擬機(jī)實(shí)現(xiàn)的一部分,類加載器對(duì)象是運(yùn)行中的程序的一部分。不同類加載器加載的類被不同的命名空間所分割。
         類加載器調(diào)用了許多Java虛擬機(jī)中其他的部分和java.lang包中的很多類。比如,類加載對(duì)象就是java.lang.ClassLoader子類 的實(shí)例,ClassLoader類中的方法可以訪問虛擬機(jī)中的類加載機(jī)制;每一個(gè)被Java虛擬機(jī)加載的類都會(huì)被表示為一個(gè) java.lang.Class類的實(shí)例。像其他對(duì)象一樣,類加載器對(duì)象和Class對(duì)象都保存在堆中,被加載的信息被保存在方法區(qū)中。
         1、加載、連接、初始化(Loading, Linking and Initialization
    類加載子系統(tǒng)不僅僅負(fù)責(zé)定位并加載類文件,他按照以下嚴(yán)格的步驟作了很多其他的事情:(具體的信息參見第七章的類的生命周期
              1)、加載:尋找并導(dǎo)入指定類型(類和接口)的二進(jìn)制信息
              2)、連接:進(jìn)行驗(yàn)證、準(zhǔn)備和解析
                   驗(yàn)證:確保導(dǎo)入類型的正確性
                   準(zhǔn)備:為類型分配內(nèi)存并初始化為默認(rèn)值
                   解析:將字符引用解析為直接飲用
              3)、初始化:調(diào)用Java代碼,初始化類變量為合適的值
         2、原始類加載器(The Primordial Class Loader
         每個(gè)Java虛擬機(jī)都必須實(shí)現(xiàn)一個(gè)原始類加載器,他能夠加載那些遵守類文件格式并且被信任的類。但是,Java虛擬機(jī)的規(guī)范并沒有定義如何加載類,這由 Java虛擬機(jī)實(shí)現(xiàn)者自己決定。對(duì)于給定類型名的類型,原始萊加載器必須找到那個(gè)類型名加“.class”的文件并加載入虛擬機(jī)中。
         3、類加載器對(duì)象
         雖然類加載器對(duì)象是Java程序的一部分,但是ClassLoader類中的三個(gè)方法可以訪問Java虛擬機(jī)中的類加載子系統(tǒng)。
              1)、protected final Class defineClass(…):使用這個(gè)方法可以出入一個(gè)字節(jié)數(shù)組,定義一個(gè)新的類型。
              2)、protected Class findSystemClass(String name):加載指定的類,如果已經(jīng)加載,就直接返回。
              3)、protected final void resolveClass(Class c)defineClass()方法只是加載一個(gè)類,這個(gè)方法負(fù)責(zé)后續(xù)的動(dòng)態(tài)連接和初始化。
         具體的信息,參見第八章連接模型 The Linking Model)。
         4、命名空間
         當(dāng)多個(gè)類加載器加載了同一個(gè)類時(shí),為了保證他們名字的唯一性,需要在類名前加上加載該類的類加載器的標(biāo)識(shí)。具體的信息,參見第八章連接模型 The Linking Model)。
    七、方法區(qū)(The Method Area
         Java虛擬機(jī)中,被加載類型的信息都保存在方法區(qū)中。這寫信息在內(nèi)存中的組織形式由虛擬機(jī)的實(shí)現(xiàn)者定義,比如,虛擬機(jī)工作在一個(gè)“little- endian”的處理器上,他就可以將信息保存為“little-endian”格式的,雖然在Java類文件中他們是以“big-endian”格式保 存的。設(shè)計(jì)者可以用最適合并地機(jī)器的表示格式來存儲(chǔ)數(shù)據(jù),以保證程序能夠以最快的速度執(zhí)行。但是,在一個(gè)只有很小內(nèi)存的設(shè)備上,虛擬機(jī)的實(shí)現(xiàn)者就不會(huì)占用 很大的內(nèi)存。
         程序中的所有線程共享一個(gè)方法區(qū),所以訪問方法區(qū)信息的方法必須是線程安全的。如果你有兩個(gè)線程都去加載一個(gè)叫Lava的類,那只能由一個(gè)線程被容許去加載這個(gè)類,另一個(gè)必須等待。
         在程序運(yùn)行時(shí),方法區(qū)的大小是可變的,程序在運(yùn)行時(shí)可以擴(kuò)展。有些Java虛擬機(jī)的實(shí)現(xiàn)也可以通過參數(shù)也訂制方法區(qū)的初始大小,最小值和最大值。
         方法區(qū)也可以被垃圾收集。因?yàn)槌绦蛑械膬?nèi)由類加載器動(dòng)態(tài)加載,所有類可能變成沒有被引用(unreferenced)的狀態(tài)。當(dāng)類變成這種狀態(tài)時(shí),他就可 能被垃圾收集掉。沒有加載的類包括兩種狀態(tài),一種是真正的沒有加載,另一個(gè)種是“unreferenced”的狀態(tài)。詳細(xì)信息參見第七章的類的生命周期 The Lifetime of a Class)。
         1、類型信息(Type Information
              每一個(gè)被加載的類型,在Java虛擬機(jī)中都會(huì)在方法區(qū)中保存如下信息:
              1)、類型的全名(The fully qualified name of the type
              2)、類型的父類型的全名(除非沒有父類型,或者弗雷形式java.lang.Object)(The fully qualified name of the typeís direct superclass
              3)、給類型是一個(gè)類還是接口(class or an interface)(Whether or not the type is a class
              4)、類型的修飾符(publicprivateprotectedstaticfinalvolatiletransient等)(The typeís modifiers
              5)、所有父接口全名的列表(An ordered list of the fully qualified names of any direct superinterfaces
              類型全名保存的數(shù)據(jù)結(jié)構(gòu)由虛擬機(jī)實(shí)現(xiàn)者定義。除此之外,Java虛擬機(jī)還要為每個(gè)類型保存如下信息:
              1)、類型的常量池(The constant pool for the type
              2)、類型字段的信息(Field information
              3)、類型方法的信息(Method information
              4)、所有的靜態(tài)類變量(非常量)信息(All class (static) variables declared in the type, except constants
              5)、一個(gè)指向類加載器的引用(A reference to class ClassLoader
              6)、一個(gè)指向Class類的引用(A reference to class Class


              1)、類型的常量池(The constant pool for the type
              常量池中保存中所有類型是用的有序的常量集合,包含直接常量(literals)如字符串、整數(shù)、浮點(diǎn)數(shù)的常量,和對(duì)類型、字段、方法的符號(hào)引用。常量池 中每一個(gè)保存的常量都有一個(gè)索引,就像數(shù)組中的字段一樣。因?yàn)槌A砍刂斜4嬷兴蓄愋褪褂玫降念愋汀⒆侄巍⒎椒ǖ淖址茫运彩莿?dòng)態(tài)連接的主要對(duì) 象。詳細(xì)信息參見第六章“The Java Class File”
              2)、類型字段的信息(Field information
              字段名、字段類型、字段的修飾符(publicprivateprotectedstaticfinalvolatiletransient等)、字段在類中定義的順序。
              3)、類型方法的信息(Method information
              方法名、方法的返回值類型(或者是void)、方法參數(shù)的個(gè)數(shù)、類型和他們的順序、字段的修飾符(publicprivateprotectedstaticfinalvolatiletransient等)、方法在類中定義的順序
              如果不是抽象和本地本法還需要保存
              方法的字節(jié)碼、方法的操作數(shù)堆棧的大小和本地變量區(qū)的大小(稍候有詳細(xì)信息)、異常列表(詳細(xì)信息參見第十七章“Exceptions”。)
              4)、類(靜態(tài))變量(Class Variables
              類變量被所有類的實(shí)例共享,即使不通過類的實(shí)例也可以訪問。這些變量綁定在類上(而不是類的實(shí)例上),所以他們是類的邏輯數(shù)據(jù)的一部分。在Java虛擬機(jī)使用這個(gè)類之前就需要為類變量(non-final)分配內(nèi)存
              常量(final)的處理方式于這種類變量(non-final)不一樣。每一個(gè)類型在用到一個(gè)常量的時(shí)候,都會(huì)復(fù)制一份到自己的常量池中。常量也像類變 量一樣保存在方法區(qū)中,只不過他保存在常量池中。(可能是,類變量被所有實(shí)例共享,而常量池是每個(gè)實(shí)例獨(dú)有的)。Non-final類變量保存為定義他的 類型數(shù)據(jù)(data for the type that declares them)的一部分,而final常量保存為使用他的類型數(shù)據(jù)(data for any type that uses them)的一部分。詳情參見第六章“The Java Class FileThe Java Class File”
              5)、指向類加載器的引用(A reference to class ClassLoader
              每一個(gè)被Java虛擬機(jī)加載的類型,虛擬機(jī)必須保存這個(gè)類型是否由原始類加載器或者類加載器加載。那些被類加載器加載的類型必須保存一個(gè)指向類加載器的引 用。當(dāng)類加載器動(dòng)態(tài)連接時(shí),會(huì)使用這條信息。當(dāng)一個(gè)類引用另一個(gè)類時(shí),虛擬機(jī)必須保存那個(gè)被引用的類型是被同一個(gè)類加載器加載的,這也是虛擬機(jī)維護(hù)不同命 名空間的過程。詳情參見第八章“The Linking Model”
              6)、指向Class類的引用(A reference to class Class
              Java虛擬機(jī)為每一個(gè)加載的類型創(chuàng)建一個(gè)java.lang.Class類的實(shí)例。你也可以通過Class類的方法:
    public static Class forName(String className)來查找或者加載一個(gè)類,并取得相應(yīng)的Class類的實(shí)例。通過這個(gè)Class類的實(shí)例,我們可以訪問Java虛擬機(jī)方法區(qū)中的信息。具體參照Class類的JavaDoc
         2、方法列表(Method Tables
         為了更有效的訪問所有保存在方法區(qū)中的數(shù)據(jù),這些數(shù)據(jù)的存儲(chǔ)結(jié)構(gòu)必須經(jīng)過仔細(xì)的設(shè)計(jì)。所有方法區(qū)中,除了保存了上邊的那些原始信息外,還有一個(gè)為了加快存 取速度而設(shè)計(jì)的數(shù)據(jù)結(jié)構(gòu),比如方法列表。每一個(gè)被加載的非抽象類,Java虛擬機(jī)都會(huì)為他們產(chǎn)生一個(gè)方法列表,這個(gè)列表中保存了這個(gè)類可能調(diào)用的所有實(shí)例 方法的引用,報(bào)錯(cuò)那些父類中調(diào)用的方法。詳情參見第八章“The Linking Model”

             八、堆
         當(dāng)Java程序創(chuàng)建一個(gè)類的實(shí)例或者數(shù)組時(shí),都在堆中為新的對(duì)象分配內(nèi)存。虛擬機(jī)中只有一個(gè)堆,所有的線程都共享他。
         1、垃圾收集(Garbage Collection
         垃圾收集是釋放沒有被引用的對(duì)象的主要方法。它也可能會(huì)為了減少堆的碎片,而移動(dòng)對(duì)象。在Java虛擬機(jī)的規(guī)范中沒有嚴(yán)格定義垃圾收集,只是定義一個(gè)Java虛擬機(jī)的實(shí)現(xiàn)必須通過某種方式管理自己的堆。詳情參見第九章“Garbage Collection”
         2、對(duì)象存儲(chǔ)結(jié)構(gòu)(Object Representation
         Java虛擬機(jī)的規(guī)范中沒有定義對(duì)象怎樣在堆中存儲(chǔ)。每一個(gè)對(duì)象主要存儲(chǔ)的是他的類和父類中定義的對(duì)象變量。對(duì)于給定的對(duì)象的引用,虛擬機(jī)必須嫩耨很快的 定位到這個(gè)對(duì)象的數(shù)據(jù)。另為,必須提供一種通過對(duì)象的引用方法對(duì)象數(shù)據(jù)的方法,比如方法區(qū)中的對(duì)象的引用,所以一個(gè)對(duì)象保存的數(shù)據(jù)中往往含有一個(gè)某種形式 指向方法區(qū)的指針。
         一個(gè)可能的堆的設(shè)計(jì)是將堆分為兩個(gè)部分:引用池和對(duì)象池。一個(gè)對(duì)象的引用就是指向引用池的本地指針。每一個(gè)引用池中的條目都包含兩個(gè)部分:指向?qū)ο蟪刂袑?duì) 象數(shù)據(jù)的指針和方法區(qū)中對(duì)象類數(shù)據(jù)的指針。這種設(shè)計(jì)能夠方便Java虛擬機(jī)堆碎片的整理。當(dāng)虛擬機(jī)在對(duì)象池中移動(dòng)一個(gè)對(duì)象的時(shí)候,只需要修改對(duì)應(yīng)引用池中 的指針地址。但是每次訪問對(duì)象的數(shù)據(jù)都需要處理兩次指針。下圖演示了這種堆的設(shè)計(jì)。在第九章的垃圾收集中的HeapOfFish Applet演示了這種設(shè)計(jì)。 
         另一種堆的設(shè)計(jì)是:一個(gè)對(duì)象的引用就是一個(gè)指向一堆數(shù)據(jù)和指向相應(yīng)對(duì)象的偏移指針。這種設(shè)計(jì)方便了對(duì)象的訪問,可是對(duì)象的移動(dòng)要變的異常復(fù)雜。下圖演示了這種設(shè)計(jì) 
         當(dāng)程序試圖將一個(gè)對(duì)象轉(zhuǎn)換為另一種類型時(shí),虛擬機(jī)需要判斷這種轉(zhuǎn)換是否是這個(gè)對(duì)象的類型,或者是他的父類型。當(dāng)程序適用instanceof語句的時(shí)候也 會(huì)做類似的事情。當(dāng)程序調(diào)用一個(gè)對(duì)象的方法時(shí),虛擬機(jī)需要進(jìn)行動(dòng)態(tài)綁定,他必須判斷調(diào)用哪一個(gè)類型的方法。這也需要做上面的判斷。
         無論虛擬機(jī)實(shí)現(xiàn)者使用哪一種設(shè)計(jì),他都可能為每一個(gè)對(duì)象保存一個(gè)類似方法列表的信息。因?yàn)樗梢蕴嵘龑?duì)象方法調(diào)用的速度,對(duì)提升虛擬機(jī)的性能非常重要,但 是虛擬機(jī)的規(guī)范中比沒有要求必須實(shí)現(xiàn)類似的數(shù)據(jù)結(jié)構(gòu)。下圖描述了這種結(jié)構(gòu)。圖中顯示了一個(gè)對(duì)象引用相關(guān)聯(lián)的所有的數(shù)據(jù)結(jié)構(gòu),包括:
              1)、一個(gè)指向類型數(shù)據(jù)的指針
              2)、一個(gè)對(duì)象的方法列表。方法列表是一個(gè)指向所有可能被調(diào)用對(duì)象方法的指針數(shù)組。方法數(shù)據(jù)包括三個(gè)部分:操作碼堆棧的大小和方法堆棧的本地變量區(qū);方法的字節(jié)碼;異常列表。
              每一個(gè)Java虛擬機(jī)中的對(duì)象必須關(guān)聯(lián)一個(gè)用于同步多線程的lock(mutex)。同一時(shí)刻,只能有一個(gè)對(duì)象擁有這個(gè)對(duì)象的鎖。當(dāng)一個(gè)擁有這個(gè)這個(gè)對(duì)象 的鎖,他就可以多次申請(qǐng)這個(gè)鎖,但是也必須釋放相應(yīng)次數(shù)的鎖才能真正釋放這個(gè)對(duì)象鎖。很多對(duì)象在整個(gè)生命周期中都不會(huì)被鎖,所以這個(gè)信息只有在需要時(shí)才需 要添加。很多Java虛擬機(jī)的實(shí)現(xiàn)都沒有在對(duì)象的數(shù)據(jù)中包含鎖定數(shù)據(jù),只是在需要時(shí)才生成相應(yīng)的數(shù)據(jù)。除了實(shí)現(xiàn)對(duì)象的鎖定,每一個(gè)對(duì)象還邏輯關(guān)聯(lián)到一 個(gè)“wait set”的實(shí)現(xiàn)。鎖定幫組線程獨(dú)立處理共享的數(shù)據(jù),不需要妨礙其他的線程。“wait set”幫組線程協(xié)作完成同一個(gè)目標(biāo)。“wait set”往往通過Object類的wait()notify()方法來實(shí)現(xiàn)。 
         垃圾收集也需要堆中的對(duì)象是否被關(guān)聯(lián)的信息。Java虛擬機(jī)規(guī)范中指出垃圾收集一個(gè)運(yùn)行一個(gè)對(duì)象的finalizer方法一次,但是容許 finalizer方法重新引用這個(gè)對(duì)象,當(dāng)這個(gè)對(duì)象再次不被引用時(shí),就不需要再次調(diào)用finalize方法。所以虛擬機(jī)也需要保存finalize方法 是否運(yùn)行過的信息。更多信息參見第九章的垃圾收集
         3、數(shù)組的保存(Array Representation
    Java 中,數(shù)組是一種完全意義上的對(duì)象,他和對(duì)象一樣保存在堆中、有一個(gè)指向Class類實(shí)例的引用。所有同一維度和類型的數(shù)組擁有同樣的Class,數(shù)組的長 度不做考慮。對(duì)應(yīng)Class的名字表示為維度和類型。比如一個(gè)整型數(shù)據(jù)的Class“[I”,字節(jié)型三維數(shù)組Class名為“[[[B”,兩維對(duì)象數(shù)據(jù) Class名為“[[Ljava.lang.Object”
    多維數(shù)組被表示為數(shù)組的數(shù)組,如下圖: 
         數(shù)組必須在堆中保存數(shù)組的長度,數(shù)組的數(shù)據(jù)和一些對(duì)象數(shù)組類型數(shù)據(jù)的引用。通過一個(gè)數(shù)組引用的,虛擬機(jī)應(yīng)該能夠取得一個(gè)數(shù)組的長度,通過索引能夠訪問特定 的數(shù)據(jù),能夠調(diào)用Object定義的方法。Object是所有數(shù)據(jù)類的直接父類。更多信息參見第六章類文件
    九、PC寄存器(程序計(jì)數(shù)器)(The Program Counter
         每一個(gè)線程開始執(zhí)行時(shí)都會(huì)被創(chuàng)建一個(gè)程序計(jì)數(shù)器。程序計(jì)數(shù)器只有一個(gè)字長(word),所以它能夠保存一個(gè)本地指針和returnValue。當(dāng)線程執(zhí)行 時(shí),程序計(jì)數(shù)器中存放了正在執(zhí)行指令的地址,這個(gè)地址可以使一個(gè)本地指針,也可以使一個(gè)從方法字節(jié)碼開始的偏移指針。如果執(zhí)行本地方法,程序計(jì)數(shù)器的值沒 有被定義。
    十、Java堆棧(The Java Stack
         當(dāng)一個(gè)線程啟動(dòng)時(shí),Java虛擬機(jī)會(huì)為他創(chuàng)建一個(gè)Java堆棧。Java堆棧用一些離散的frame類紀(jì)錄線程的狀態(tài)。Java虛擬機(jī)堆Java堆棧的操作只有兩種:壓入和彈出frames
         線程中正在執(zhí)行的方法被稱為當(dāng)前方法(current method),當(dāng)前方法所對(duì)應(yīng)的frame被稱為當(dāng)前幀(current frame)。定義當(dāng)前方法的類被稱為當(dāng)前類(current class),當(dāng)前類的常量池被稱為當(dāng)前常量池(current constant pool.)。當(dāng)線程執(zhí)行時(shí),Java虛擬機(jī)會(huì)跟蹤當(dāng)前類和當(dāng)前常量池。但線程操作保存在幀中的數(shù)據(jù)時(shí),他只操作當(dāng)前幀的數(shù)據(jù)。
         當(dāng)線程調(diào)用一個(gè)方法時(shí),虛擬機(jī)會(huì)生成一個(gè)新的幀,并壓入線程的Java堆棧。這個(gè)新的幀變成當(dāng)前幀。當(dāng)方法執(zhí)行時(shí),他使用當(dāng)前幀保存方法的參數(shù)、本地變 量、中間結(jié)構(gòu)和其他數(shù)據(jù)。方法有兩種退出方式:正常退出和異常推出。無論方法以哪一種方式推出,Java虛擬機(jī)都會(huì)彈出并丟棄方法的幀,上一個(gè)方法的幀變 為當(dāng)前幀。
         所有保存在幀中的數(shù)據(jù)都只能被擁有它的線程訪問,線程不能訪問其他線程的堆棧中的數(shù)據(jù)。所以,訪問方法的本地變量時(shí),不需要考慮多線程同步。
         和方法區(qū)、堆一樣,Java堆棧不需要連續(xù)的內(nèi)存空間,它可以被保存在一個(gè)分散的內(nèi)存空間或者堆上。堆棧具體的數(shù)據(jù)和長度都有Java虛擬機(jī)的實(shí)現(xiàn)者自己定義。一些實(shí)現(xiàn)可能提供了執(zhí)行堆棧最大值和最小值的方法。
    十一、堆棧幀(The Stack Frame
         堆棧幀包含三部分:本地變量、操作數(shù)堆棧和幀數(shù)據(jù)。本地變量和操作數(shù)堆棧的大小都是一字(word)為單位的,他們?cè)诰幾g就已經(jīng)確定。幀數(shù)據(jù)的大小取決于 不同的實(shí)現(xiàn)。當(dāng)程序調(diào)用一個(gè)方法時(shí),虛擬機(jī)從類數(shù)據(jù)中取得本地變量和操作數(shù)堆棧的大小,創(chuàng)建一個(gè)合適大小和幀,然后壓入Java堆棧中。
         1、本地變量(Local Variables
         本地變量在Java堆棧幀中被組織為一個(gè)從0計(jì)數(shù)的數(shù)組,指令通過提供他們的索引從本地變量區(qū)中取得相應(yīng)的值。Int,float,reference, returnValue占一個(gè)字,byte,short,char被轉(zhuǎn)換成int然后存儲(chǔ),longdoubel占兩個(gè)字。
         指令通過提供兩個(gè)字索引中的前一個(gè)來取得long,doubel的值。比如一個(gè)long的值存儲(chǔ)在索引34上,指令就可以通過3來取得這個(gè)long類型的值。
         本地變量區(qū)中包含了方法的參數(shù)和本地變量。編譯器將方法的參數(shù)以他們申明的順序放在數(shù)組的前面。但是編譯器卻可以將本地變量任意排列在本地變量數(shù)組中,甚至兩個(gè)本地變量可以公用一個(gè)地址,比如,當(dāng)兩個(gè)本地變量在兩個(gè)不交疊的區(qū)域內(nèi),就像循環(huán)變量i,j
         虛擬機(jī)的實(shí)現(xiàn)者可以使用任何結(jié)構(gòu)來描述本地變量區(qū)中的數(shù)據(jù),虛擬機(jī)規(guī)范中沒有定義如何存儲(chǔ)longdoubel
         2、操作數(shù)堆棧(Operand Stack
         向本地變量一樣,操作數(shù)堆棧也被組織為一個(gè)以字為單位的數(shù)組。但是不像本地變量那樣通過索引訪問,而是通過pushpop值來實(shí)現(xiàn)訪問的。如果一個(gè)指令push一個(gè)值到堆棧中,那么下一個(gè)指令就可以pop并且使用這個(gè)值。
         操作數(shù)堆棧不像程序計(jì)數(shù)器那樣不可以被指令直接訪問,指令可以直接訪問操作數(shù)堆棧。Java虛擬機(jī)是一個(gè)以堆棧為基礎(chǔ),而不是以寄存器為基礎(chǔ)的,因?yàn)樗?/span> 指令從堆棧中取得操作數(shù),而不是同寄存器中。當(dāng)然,指令也可以從其他地方去的操作數(shù),比如指令后面的操作碼,或者常量池。但是Java虛擬機(jī)指令主要是從 操作數(shù)堆棧中取得他們需要的操作數(shù)。
         Java虛擬機(jī)將操作數(shù)堆棧視為工作區(qū),很多指令通過先從操作數(shù)堆棧中pop值,在處理完以后再將結(jié)果push回操作數(shù)堆棧。一個(gè)add的指令執(zhí)行過程如 下圖所示:先執(zhí)行iload_0iload_1兩條指令將需要相加的兩個(gè)數(shù),從本地方法區(qū)中取出,并push到操作數(shù)堆棧中;然后執(zhí)行iadd指令,現(xiàn) pop出兩個(gè)值,相加,并將結(jié)果pusp進(jìn)操作數(shù)堆棧中;最后執(zhí)行istore_2指令,pop出結(jié)果,賦值到本地方法區(qū)中。 
         3、幀數(shù)據(jù)(Frame Data
         處理本地變量和操作數(shù)堆棧以外,java堆棧幀還包括了為了支持常量池,方法返回值和異常分發(fā)需要的數(shù)據(jù),他們被保存在幀數(shù)據(jù)中。
         當(dāng)虛擬機(jī)遇到使用指向常量池引用的指令時(shí),就會(huì)通過幀數(shù)據(jù)中指向常量區(qū)的指針來訪問所需要的信息。前面提到過,常量區(qū)中的引用在最開始時(shí)都是符號(hào)引用。即使當(dāng)虛擬機(jī)檢查這些引用時(shí),他們也是字符引用。所以虛擬機(jī)需要在這時(shí)轉(zhuǎn)換這個(gè)引用。
         當(dāng)一個(gè)方法正常返回時(shí),虛擬機(jī)需要重建那個(gè)調(diào)用這個(gè)方法的方法的堆棧幀。如果執(zhí)行完的方法有返回值,虛擬機(jī)就需要將這個(gè)值push進(jìn)調(diào)用方法的哪個(gè)操作數(shù)堆棧中。
         幀數(shù)據(jù)中也包含虛擬機(jī)用來處理異常的異常表的引用。異常表定義了一個(gè)被catch語句保護(hù)的一段字節(jié)碼。每一個(gè)異常表中的個(gè)體又包含了需要保護(hù)的字節(jié)瑪?shù)?/span> 范圍,和異常被捕捉到時(shí)需要執(zhí)行的字節(jié)碼的位置。當(dāng)一個(gè)方法拋出一個(gè)異常時(shí),Java虛擬機(jī)就是用異常表去判斷如何處理這個(gè)異常。如果虛擬機(jī)找到了一個(gè)匹 配的catch,他就會(huì)將控制權(quán)交給catch語句。如果沒有找到匹配的catch,方法就會(huì)異常返回,然后再調(diào)用的方法中繼續(xù)這個(gè)過程。
         除了以上的三個(gè)用途外,幀數(shù)據(jù)還可能包含一些依賴于實(shí)現(xiàn)的數(shù)據(jù),比如調(diào)試的信息。
    十二、本地方法堆棧
         本地方法區(qū)依賴于虛擬機(jī)的不同實(shí)現(xiàn)。虛擬機(jī)的實(shí)現(xiàn)者可以自己決定使用哪一種機(jī)制去執(zhí)行本地方法。
         任何本地方法接口(Native Method Interface)都使用某種形式的本地方法堆棧。 
    十三、執(zhí)行引擎
         一個(gè)java虛擬機(jī)實(shí)現(xiàn)的核心就是執(zhí)行引擎。在Java虛擬機(jī)規(guī)范,執(zhí)行引擎被描述為一系列的指令。對(duì)于每一個(gè)指令,規(guī)范都描述了他們應(yīng)該做什么,但是沒有說要如何去做。
         1、指令集
         Java虛擬機(jī)中一個(gè)方法的字節(jié)碼流就是一個(gè)指令的序列。每一個(gè)指令由一個(gè)字節(jié)的操作碼(Opcode)和可能存在的操作數(shù)(Operands)。操作 碼指示去做什么,操作數(shù)提供一些執(zhí)行這個(gè)操作碼可能需要的額外的信息。一個(gè)抽象的執(zhí)行引擎每次執(zhí)行一個(gè)指令。這個(gè)過程發(fā)生在每一個(gè)執(zhí)行的線程中。
    有時(shí),執(zhí)行引擎可能會(huì)遇到一個(gè)需要調(diào)用本地方法的指令,在這種情況下,執(zhí)行引擎會(huì)去試圖調(diào)用本地方法,但本地方法返回時(shí),執(zhí)行引擎會(huì)繼續(xù)執(zhí)行字節(jié)碼流中的下一個(gè)指令。本地方法也可以看成對(duì)Java虛擬機(jī)中的指令集的一種擴(kuò)充。
         決定下一步執(zhí)行那一條指令也是執(zhí)行引擎工作的一部分。執(zhí)行引擎有三種方法去取得下一條指令。多數(shù)指令會(huì)執(zhí)行跟在他會(huì)面的指令;一些像goto return的指令,會(huì)在他們執(zhí)行的時(shí)候決定他們的下一條指令;當(dāng)一個(gè)指令拋出異常時(shí),執(zhí)行引擎通過匹配catch語句來決定下一條應(yīng)該執(zhí)行的指令。
         平臺(tái)獨(dú)立性、網(wǎng)絡(luò)移動(dòng)性、安全
    性左右了Java虛擬機(jī)指令集的設(shè)計(jì)。平臺(tái)獨(dú)立性是指令集設(shè)計(jì)的主要影響因素之一。基于堆棧的結(jié)構(gòu)使得Java虛擬機(jī)可以在 更多的平臺(tái)上實(shí)現(xiàn)。更小的操作碼,緊湊的結(jié)構(gòu)使得字節(jié)碼可以更有效的利用網(wǎng)絡(luò)帶寬。一次性的字節(jié)碼驗(yàn)證,使得字節(jié)碼更安全,而不影響太多的性能。
         2、執(zhí)行技術(shù)
         許多種執(zhí)行技術(shù)可以用在Java虛擬機(jī)的實(shí)現(xiàn)中:解釋執(zhí)行,及時(shí)編譯(just-in-time compiling),hot-spot compiling,native execution in silicon
         3、線程
         Java虛擬機(jī)規(guī)范定義了一種為了在更多平臺(tái)上實(shí)現(xiàn)的線程模型。Java線程模型的一個(gè)目標(biāo)時(shí)可以利用本地線程。利用本地線程可以讓Java程序中的線程能過在多處理器機(jī)器上真正的同時(shí)執(zhí)行。
         Java線程模型的一個(gè)代價(jià)就是線程優(yōu)先級(jí),一個(gè)Java線程可以在1-10的優(yōu)先級(jí)上運(yùn)行。1最低,10最高。如果設(shè)計(jì)者使用了本地線程,他們可能將這 10個(gè)優(yōu)先級(jí)映射到本地優(yōu)先級(jí)上。Java虛擬機(jī)規(guī)范只定義了,高一點(diǎn)優(yōu)先級(jí)的線程可以卻一些cpu時(shí)間,低優(yōu)先級(jí)的線程在所有高優(yōu)先級(jí)線程都堵塞時(shí),也 可以獲取一些cpu時(shí)間,但是這沒有保證:低優(yōu)先級(jí)的線程在高優(yōu)先級(jí)線程沒有堵塞時(shí)不可以獲得一定的cpu時(shí)間。因此,如果需要在不同的線程間協(xié)作,你必 須使用的同步(synchronizatoin
         同步意味著兩個(gè)部分:對(duì)象鎖(object locking)和線程等待、激活(thread wait and notify)。對(duì)象鎖幫助線程可以不受其他線程的干擾。線程等待、激活可以讓不同的線程進(jìn)行協(xié)作。
         Java虛擬機(jī)的規(guī)范中,Java線程被描述為變量、主內(nèi)存、工作內(nèi)存。每一個(gè)Java虛擬機(jī)的實(shí)例都有一個(gè)主內(nèi)存,他包含了所有程序的變量:對(duì)象、數(shù)組合類變量。每一個(gè)線程都有自己的工作內(nèi)存,他保存了哪些他可能用到的變量的拷貝。規(guī)則:
              1)、從主內(nèi)存拷貝變量的值到工作內(nèi)存中
              2)、將工作內(nèi)存中的值寫會(huì)主內(nèi)存中
         如果一個(gè)變量沒有被同步化,線程可能以任何順序更新主內(nèi)存中的變量。為了保證多線程程序的正確的執(zhí)行,必須使用同步機(jī)制。
    十四、本地方法接口(Native Method Interface
         Java虛擬機(jī)的實(shí)現(xiàn)并不是必須實(shí)現(xiàn)本地方法接口。一些實(shí)現(xiàn)可能根本不支持本地方法接口。Sun的本地方法接口是JNI(Java Native Interface)
    十五、現(xiàn)實(shí)中的機(jī)器(The Real Machine
    十六、數(shù)學(xué)方法:仿真(Eternal Math : A Simulation)

    posted on 2008-01-13 13:37 安文豪 閱讀(611) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     

    <2008年1月>
    303112345
    6789101112
    13141516171819
    20212223242526
    272829303112
    3456789

    常用鏈接

    留言簿(6)

    隨筆檔案(28)

    文章分類(3)

    文章檔案(4)

    最新隨筆

    搜索

    •  

    積分與排名

    • 積分 - 86469
    • 排名 - 666

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 日韩久久无码免费毛片软件| 亚洲精品无码MV在线观看| 国产在线jyzzjyzz免费麻豆 | 亚洲午夜福利精品久久| 国产成人3p视频免费观看| 日韩黄色免费观看| 日韩免费观看的一级毛片| 国产女高清在线看免费观看| 日本v片免费一区二区三区 | 三年片在线观看免费西瓜视频| 羞羞视频免费网站在线看| 国产精品免费看久久久香蕉| 久久国产美女免费观看精品| 中国精品一级毛片免费播放| 99精品视频免费| 99re在线视频免费观看| 18pao国产成视频永久免费| 国产免费的野战视频| 无码日韩人妻av一区免费| 午夜精品在线免费观看| 国产精品酒店视频免费看| 啊v在线免费观看| 黑人大战亚洲人精品一区 | 国产麻豆免费观看91| 四虎影视在线永久免费观看| 亚洲区小说区图片区| 亚洲国产精品无码久久一线| 亚洲天堂男人天堂| 亚洲六月丁香婷婷综合| 欧洲亚洲国产精华液| 一级白嫩美女毛片免费| 99久久国产精品免费一区二区| 免费无码一区二区三区| 免费无码黄十八禁网站在线观看| 日韩免费视频在线观看| 亚洲日韩国产精品第一页一区| 久久久久亚洲AV片无码下载蜜桃| 亚洲日韩一区精品射精| 一级看片免费视频囗交| 亚洲一区在线免费观看| 日本免费观看网站|