海闊天空

          I'm on my way!
          隨筆 - 17, 文章 - 69, 評論 - 21, 引用 - 0
          數(shù)據(jù)加載中……

          java程序的運(yùn)行機(jī)制

          (一)  Java應(yīng)用程序的開發(fā)周期包括編譯、下載、解釋和執(zhí)行幾個(gè)部分。Java編譯程序?qū)? Java源程序翻譯為JVM可執(zhí)行代碼--字節(jié)碼。這一編譯過程同C/C++的編譯有些不同。當(dāng)C編譯器編譯生成一個(gè)對象的代碼時(shí),該代碼是為在某一特定 硬件平臺運(yùn)行而產(chǎn)生的。因此,在編譯過程中,編譯程序通過查表將所有對符號的引用轉(zhuǎn)換為特定的內(nèi)存偏移量,以保證程序運(yùn)行。Java編譯器卻不將對變量和 方法的引用編譯為數(shù)值引用,也不確定程序執(zhí)行過程中的內(nèi)存布局,而是將這些符號引用信息保留在字節(jié)碼中,由解釋器在運(yùn)行過程中創(chuàng)立內(nèi)存布局,然后再通過查 表來確定一個(gè)方法所在的地址。這樣就有效的保證了Java的可移植性和安全性。

          運(yùn)行JVM字節(jié)碼的工作是由解釋器( java命令 )來完成的。解釋執(zhí)行過程分三部進(jìn)行:代碼的裝入、代碼的校驗(yàn)和代碼的執(zhí)行。裝入代碼的工作由"類裝載器"(class loader)完成。類裝載器負(fù)責(zé)裝入運(yùn)行一個(gè)程序需要的所有代碼,這也包括程序代碼中的類所繼承的類和被其調(diào)用的類。當(dāng)類裝載器裝入一個(gè)類時(shí),該類被放 在自己的名字空間中。除了通過符號引用自己名字空間以外的類,類之間沒有其他辦法可以影響其他類。在本臺計(jì)算機(jī)上的所有類都在同一地址空間內(nèi),而所有從外 部引進(jìn)的類,都有一個(gè)自己獨(dú)立的名字空間。這使得本地類通過共享相同的名字空間獲得較高的運(yùn)行效率,同時(shí)又保證它們與從外部引進(jìn)的類不會相互影響。當(dāng)裝入 了運(yùn)行程序需要的所有類后,解釋器便可確定整個(gè)可執(zhí)行程序的內(nèi)存布局。解釋器為符號引用同特定的地址空間建立對應(yīng)關(guān)系及查詢表。通過在這一階段確定代碼的 內(nèi)存布局,Java很好地解決了由超類改變而使子類崩潰的問題,同時(shí)也防止了代碼對地址的非法訪問。

           

          隨后,被裝入的代碼由字節(jié)碼校驗(yàn)器進(jìn)行檢查。校驗(yàn)器可發(fā)現(xiàn)操作數(shù)棧溢出,非法數(shù)據(jù)類型轉(zhuǎn)化等多種錯(cuò)誤。通過校驗(yàn)后,代碼便開始執(zhí)行了。

           

          Java字節(jié)碼的執(zhí)行有兩種方式:

          1.即時(shí)編譯方式:解釋器先將字節(jié)碼編譯成機(jī)器碼,然后再執(zhí)行該機(jī)器碼。

          2.解釋執(zhí)行方式:解釋器通過每次解釋并執(zhí)行一小段代碼來完成Java字節(jié)碼程序的所有操作。

           

          通常采用的是第二種方法。由于JVM規(guī)格描述具有足夠的靈活性,這使得將字節(jié)碼翻譯為機(jī)器代碼的工作

          具有較高的效率。對于那些對運(yùn)行速度要求較高的應(yīng)用程序,解釋器可將Java字節(jié)碼即時(shí)編譯為機(jī)器碼,從而很好地保證了Java代碼的可移植性和高性能。

          (二)JVM規(guī)格描述
          JVM的設(shè)計(jì)目標(biāo)是提供一個(gè)基于抽象規(guī)格描述的計(jì)算機(jī)模型,為解釋程序開發(fā)人員提很好的靈活性,同時(shí)也確保Java代碼可在符合該規(guī)范的任何系統(tǒng)上運(yùn)行。JVM對其實(shí)現(xiàn)的某些方面給出了具體的定義,特別是對Java可執(zhí)行代碼,即字節(jié)碼(Bytecode)的格式給出了明確的規(guī)格。這一規(guī)格包括操作碼和操作數(shù)的語法和數(shù)值、標(biāo)識符的數(shù)值表示方式、以及Java類文件中的Java對象、常量緩沖池在JVM的存儲映象。這些定義為JVM解釋器開發(fā)人員提供了所需的信息和開發(fā)環(huán)境。Java的設(shè)計(jì)者希望給開發(fā)人員以隨心所欲使用Java的自由。
          JVM定義了控制Java代碼解釋執(zhí)行和具體實(shí)現(xiàn)的五種規(guī)格,它們是:
          JVM指令系統(tǒng)
          JVM寄存器
          JVM棧結(jié)構(gòu)
          JVM碎片回收堆
          JVM存儲區(qū)
          2.1JVM指令系統(tǒng)
          JVM指令系統(tǒng)同其他計(jì)算機(jī)的指令系統(tǒng)極其相似。Java指令也是由 操作碼和操作數(shù)兩部分組成。操作碼為8位二進(jìn)制數(shù),操作數(shù)進(jìn)緊隨在操作碼的后面,其長度根據(jù)需要而不同。操作碼用于指定一條指令操作的性質(zhì)(在這里我們采 用匯編符號的形式進(jìn)行說明),如iload表示從存儲器中裝入一個(gè)整數(shù),anewarray表示為一個(gè)新數(shù)組分配空間,iand表示兩個(gè)整數(shù)的" 與",ret用于流程控制,表示從對某一方法的調(diào)用中返回。當(dāng)長度大于8位時(shí),操作數(shù)被分為兩個(gè)以上字節(jié)存放。JVM采用了"big endian"的編碼方式來處理這種情況,即高位bits存放在低字節(jié)中。這同 Motorola及其他的RISC CPU采用的編碼方式是一致的,而與Intel采用的"little endian "的編碼方式即低位bits存放在低位字節(jié)的方法不同。
          Java指令系統(tǒng)是以Java語言的實(shí)現(xiàn)為目的設(shè)計(jì)的,其中包含了用于調(diào)用方法和監(jiān)視多先程系統(tǒng)的指令。Java的8位操作碼的長度使得JVM最多有256種指令,目前已使用了160多種操作碼。
          2.2JVM指令系統(tǒng)
          所有的CPU均包含用于保存系統(tǒng)狀態(tài)和處理器所需信息的寄存器組。如果虛擬機(jī)定義較多的寄存器,便可以從中得到更多的信息而不必對棧或內(nèi)存進(jìn)行訪問,這 有利于提高運(yùn)行速度。然而,如果虛擬機(jī)中的寄存器比實(shí)際CPU的寄存器多,在實(shí)現(xiàn)虛擬機(jī)時(shí)就會占用處理器大量的時(shí)間來用常規(guī)存儲器模擬寄存器,這反而會降 低虛擬機(jī)的效率。針對這種情況,JVM只設(shè)置了4個(gè)最為常用的寄存器。它們是:
          pc程序計(jì)數(shù)器
          optop操作數(shù)棧頂指針
          frame當(dāng)前執(zhí)行環(huán)境指針
          vars指向當(dāng)前執(zhí)行環(huán)境中第一個(gè)局部變量的指針
          所有寄存器均為32位。pc用于記錄程序的執(zhí)行。optop,frame和vars用于記錄指向Java棧區(qū)的指針。
          2.3JVM棧結(jié)構(gòu)
          作為基于棧結(jié)構(gòu)的計(jì)算機(jī),Java棧是JVM存儲信息的主要方法。當(dāng)JVM得到一個(gè)Java字節(jié)碼應(yīng)用程序后,便為該代碼中一個(gè)類的每一個(gè)方法創(chuàng)建一個(gè)棧框架,以保存該方法的狀態(tài)信息。每個(gè)棧框架包括以下三類信息:
          局部變量
          執(zhí)行環(huán)境
          操作數(shù)棧
          局部變量用于存儲一個(gè)類的方法中所用到的局部變量。vars寄存器指向該變量表中的第一個(gè)局部變量。
          執(zhí)行環(huán)境用于保存解釋器對Java字節(jié)碼進(jìn)行解釋過程中所需的信息。它們是:上次調(diào)用的方法、局部變量指針和操作數(shù)棧的棧頂和棧底指針。執(zhí)行環(huán)境是一個(gè) 執(zhí)行一個(gè)方法的控制中心。例如:如果解釋器要執(zhí)行iadd(整數(shù)加法),首先要從frame寄存器中找到當(dāng)前執(zhí)行環(huán)境,而后便從執(zhí)行環(huán)境中找到操作數(shù)棧, 從棧頂彈出兩個(gè)整數(shù)進(jìn)行加法運(yùn)算,最后將結(jié)果壓入棧頂。
          操作數(shù)棧用于存儲運(yùn)算所需操作數(shù)及運(yùn)算的結(jié)果。
          2.4JVM碎片回收堆
          Java類的實(shí)例所需的存儲空間是在堆上分配的。解釋器具體承擔(dān)為類實(shí)例分配空間的工作。解釋器在為一個(gè)實(shí)例分配完存儲空間后,便開始記錄對該實(shí)例所占用的內(nèi)存區(qū)域的使用。一旦對象使用完畢,便將其回收到堆中。
          在Java語言中,除了new語句外沒有其他方法為一對象申請和釋放內(nèi)存。對內(nèi)存進(jìn)行釋放和回收的工作是由Java運(yùn)行系統(tǒng)承擔(dān)的。這允許Java運(yùn)行 系統(tǒng)的設(shè)計(jì)者自己決定碎片回收的方法。在SUN公司開發(fā)的Java解釋器和Hot Java環(huán)境中,碎片回收用后臺線程的方式來執(zhí)行。這不但為運(yùn)行系統(tǒng)提供了良好的性能,而且使程序設(shè)計(jì)人員擺脫了自己控制內(nèi)存使用的風(fēng)險(xiǎn)。
          2.5JVM存儲區(qū)
          JVM有兩類存儲區(qū):常量緩沖池和方法區(qū)。常量緩沖池用于存儲類名稱、方法和字段名稱以及串常量。方法區(qū)則用于存儲Java方法的字節(jié)碼。對于這兩種存 儲區(qū)域具體實(shí)現(xiàn)方式在JVM規(guī)格中沒有明確規(guī)定。這使得Java應(yīng)用程序的存儲布局必須在運(yùn)行過程中確定,依賴于具體平臺的實(shí)現(xiàn)方式。
          JVM是為Java字節(jié)碼定義的一種獨(dú)立于具體平臺的規(guī)格描述,是Java平臺獨(dú)立性的基礎(chǔ)。目前的JVM還存在一些限制和不足,有待于進(jìn)一步的完善,但無論如何,JVM的思想是成功的。
          對比分析:如果把Java原程序想象成我們的C++原程序,Java原程序編譯后生成的字節(jié)碼就相當(dāng)于C++原程序編譯后的80x86的機(jī)器碼(二進(jìn)制程序文件),JVM虛擬機(jī)相當(dāng)于80x86計(jì)算機(jī)系統(tǒng),Java解釋器相當(dāng)于80x86CPU。在80x86CPU上運(yùn)行的是機(jī)器碼,在Java解釋器上運(yùn)行的是Java字節(jié)碼。
          Java解釋器相當(dāng)于運(yùn)行Java字節(jié)碼的“CPU”,但該“CPU”不是通過硬件實(shí)現(xiàn)的,而是用軟件實(shí)現(xiàn)的。Java解釋器實(shí)際上就是特定的平臺下的 一個(gè)應(yīng)用程序。只要實(shí)現(xiàn)了特定平臺下的解釋器程序,Java字節(jié)碼就能通過解釋器程序在該平臺下運(yùn)行,這是Java跨平臺的根本。當(dāng)前,并不是在所有的平 臺下都有相應(yīng)Java解釋器程序,這也是Java并不能在所有的平臺下都能運(yùn)行的原因,它只能在已實(shí)現(xiàn)了Java解釋器程序的平臺下運(yùn)行。

           

          Java宣稱的一處編寫隨處運(yùn)行就是由JVM來完成. 在sun的網(wǎng)站上你可以下載到基于各種cpu和各種操作系統(tǒng)的Jdk和jre的下載版本,只要尋找到合適你使用的版本,以前你所編寫的class文件copy到其他的機(jī)器上可以直接運(yùn)行,不需要再編譯.

           

          其實(shí)j2se是一種規(guī)范,這種規(guī)范約定了其跨平臺執(zhí)行的所需要關(guān)注很多實(shí)現(xiàn),基于該規(guī)范開發(fā)人員可以任意編寫自己的Java代碼而不需要關(guān)心這個(gè)程序可能在其他的機(jī)器和cpu上無法很好運(yùn)行問題.

           

          其實(shí)你也可以看到Ibm和Weblogic都有基于j2se規(guī)范的自己實(shí)現(xiàn)的Java 虛擬機(jī) . 而且Sun所宣稱的不需要編譯而可以直接用class文件在各個(gè)JVM上直接運(yùn)行并不精確,博格曾經(jīng)遇到過用sun jre開發(fā)的class文件在ibm jre上有一個(gè)自動轉(zhuǎn)換的過程,然后這個(gè)類可以很好的工作了,幸好這種情況是自動完成,否則我們又要陷入類似于各種c c++的版本編譯器兼容性問題中.

           

          以下下摘錄了幾個(gè)主要的概念:

           

          JVM Java Virtual Machine(Java虛擬機(jī)),它是一個(gè)虛構(gòu)出來的計(jì)算機(jī),是通過在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來實(shí)現(xiàn)的。 Java虛擬機(jī)有自己完善的硬件架構(gòu),如處理器、堆棧、寄存器等,還具有相應(yīng)的指令系統(tǒng)。JVM屏蔽了與具體操作系統(tǒng)平臺相關(guān)的信息,使得Java程序只 需生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼),就可以在多種平臺上不加修改地運(yùn)行。Java虛擬機(jī)在執(zhí)行字節(jié)碼時(shí),實(shí)際上最終還是把字節(jié)碼解釋成具 體平臺上的機(jī)器指令執(zhí)行。

           

          JRE Java Runtime Environment(Java運(yùn)行環(huán)境),運(yùn)行JAVA程序所必須的環(huán)境的集合,包含JVM標(biāo)準(zhǔn)實(shí)現(xiàn)及Java核心類庫。

           

          JSDK Java Software Development Kit,和JDK以及J2SE等同。

           

          JDK Java Development Kit(Java開發(fā)工具包):包括運(yùn)行環(huán)境、編譯工具及其它工具、源代碼等,基本上和J2SE等同。

           

          J2ME Java 2 Micro Edition(JAVA2精簡版)API規(guī)格基于J2SE ,但是被修改為可以適合某種產(chǎn)品的單一要求。J2ME使JAVA 程序可以很方便的應(yīng)用于電話卡、尋呼機(jī)等小型設(shè)備,它包括兩種類型的組件,即配置(configuration)和描述(profile)。

           

          J2EE Java 2 Enterprise Edition(JAVA2企業(yè)版),使用Java進(jìn)行企業(yè)開發(fā)的一套擴(kuò)展標(biāo)準(zhǔn),必須基于J2SE,提供一個(gè)基于組件設(shè)計(jì)、開發(fā)、集合、展開企業(yè)應(yīng)用的途 徑。J2EE 平臺提供了多層、分布式的應(yīng)用模型,重新利用組件的能力,統(tǒng)一安全的模式以及靈活的處理控制能力。 J2EE包括EJB, JTA, JDBC, JCA, JMX, JNDI, JMS, JavaMail, Servlet, JSP等規(guī)范。

           

          J2SE Java 2 Standard Edition(JAVA2標(biāo)準(zhǔn)版),用來開發(fā)Java程序的基礎(chǔ),包括編譯器、小工具、運(yùn)行環(huán)境,SUN發(fā)布的標(biāo)準(zhǔn)版本中還包括核心類庫的所有源代碼。


          摘自:http://www.diybl.com/course/3_program/java/javajs/20090304/157613.html

          posted on 2009-08-22 09:52 石頭@ 閱讀(6894) 評論(0)  編輯  收藏 所屬分類: java_base

          主站蜘蛛池模板: 乌拉特后旗| 麟游县| 康乐县| 阜阳市| 莱州市| 吴桥县| 柞水县| 鹤峰县| 涞水县| 西华县| 兴宁市| 普安县| 易门县| 绥江县| 阳朔县| 乡城县| 白河县| 隆昌县| 浠水县| 德清县| 高平市| 禄丰县| 南城县| 和硕县| 兴安县| 博客| 洞口县| 阿巴嘎旗| 白水县| 金溪县| 龙门县| 凉山| 龙岩市| 水城县| 克山县| 高密市| 钦州市| 双桥区| 哈巴河县| 内丘县| 闻喜县|