日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java虚拟机是什么

發布時間:2024/9/30 java 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java虚拟机是什么 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://boy00fly.iteye.com/blog/1095263


要理解java虛擬機,你首先必須意識到,當你說“Java虛擬機”時,可能指的是如下三個不同的東西:

1. 抽象規范

2.?一個具體的實現

3.?一個運行中的虛擬機實例

?

?? ? ? ? ? Java虛擬機抽象規范僅僅是一個概念,在Tim Lindholm和Frank Yellin編著的《The Java Virtual Machine Specification》一書中詳細地描述了它。而該規范的具體實現,可能來自多個提供商,并存在于多個平臺。他或者完全用軟件實現,或者以硬件和軟件結合的方式來實現。當運行一個Java程序的同時,也就是運行了一個Java虛擬機實例。每個Java程序都運行于某個具體的Java虛擬機實現的實例上。

?

Java虛擬機的生命周期

?

??一個運行時的Java虛擬機實例的天職就是:負責運行一個Java程序。當啟動一個Java程序時,一個虛擬機實例也就誕生了。當該程序關閉退出是,這個虛擬機實例也就隨之消亡。如果在同一個計算機上同時運行三個程序,將得到三個Java虛擬機實例。每個Java程序都運行于它自己的Java虛擬機實例中。

??Java虛擬機實例通過調用某個初始類的main()方法來運行一個Java程序,此方法將作為該程序初始線程的啟動,任何其他的線程都是由這個初始線程啟動的。

??在Java虛擬機內部有兩種線程:守護線程與非守護線程。守護線程通常是由虛擬機自己使用的,比如執行垃圾收集任務的線程。但是,Java程序也可以把他創建的任何線程標記為守護線程。而Java程序中的初始線程---------就是開始于main()的那個,是非守護進程。只要還有非守護線程在運行,那么這個Java程序也在繼續運行(虛擬機仍然存活)。當該程序中所有的非守護線程都終止時,虛擬機實例將自動退出。假若安全管理器允許,程序本身也能夠通過調用Runtime類或者System類的exit()方法來退出。

?


Java虛擬機體系結構

從上圖可以看得出來,JVM中包含:

?

?1.?Class Loader 類加載器

?

?? 所有的class文件必須被加載后才能在jvm中運行,關于jvm的類加載器,在其他章節中重點描述。

?

2. ?Runtime Data Areas 運行數據區

?

?? ? 運行時數據區分為:method area(本地方法區)、heap(堆)、java stacks(Java 棧)、 pc registers(pc寄存器)、 native method stacks(本地方法棧)

?

?? ? 下面來依次解釋下上述內容:

?

?? Method area(方法區)

?

在Java虛擬機中,關于被裝載類型的信息存儲在一個邏輯上被稱為方法區的內存中。當虛擬機狀態某個類型時,它使用類裝載器定位相應的class文件,然后讀入這個class文件------一個線性二進制數據流。然后將它傳輸到虛擬機中。緊接著虛擬機提取其中的類型信息,并將這些信息存儲到方法區。該類型中的類(靜態)變量同樣也是存儲在方法區中。

?

Java虛擬機在內部如何存儲類型信息,這是由具體實現的設計者來決定的。比如,在class文件中,多字節總是以高位在前(即代表較大數的字節在前)的順序儲存。但是這些數據被引入到方法區后,虛擬機可以以任何方式存儲它。假設某個實現是運行在低位優先的處理器上,那么它很可能會把多字節以低位優先的順序存儲到方法區中。

?

當虛擬機運行Java程序時,它會查找使用存儲在方法區中的類型信息。設計者應當為類型信息的內部設計適當的數據結構,以盡可能在保持虛擬機小巧緊湊的同事加快程序的運行效率。如果正在設計一個需要在少量內存的限制中操作的實現,設計則可能會決定以犧牲某些運行速度來換取緊湊性。另外一方面,如果設計一個將在虛擬內存系統中運行的實現,設計者可能會決定在方法去中保存一些冗余的信息,以此來加快執行 速度。(如果底層主機沒有提供虛擬內存,但是提供了一個硬盤,設計者可能會在實現中穿件一個虛擬內存系統。)Java虛擬機的設計者可以根據目標平臺的資源限制和需求,在空間和時間上作出權衡,選擇實現什么樣的數據結構和數據組織。

?

由于所有線程都共享方法區,因此它們對方法區數據的訪問必須被設計為是線程安全的。比如,假設同時有連個線程都企圖訪問一個名為Lava的類,而這個類還沒有被裝入虛擬機,那么這是只應該有一個線程去裝載它,而另外一個線程則只能等待。

?

方法區的大小不必是固定的,虛擬機可以根據應用的需要動態調整。同樣,方法區也不必是連續的,方法區可以在一個堆(甚至是虛擬機自己的堆)中自由分配。另外,虛擬機也可以允許用戶或者程序員指定方法區的初始化大小以及最小和最大尺寸等。

?

方法區也可以被垃圾收集,因為虛擬機允許通過用戶定義的類裝載器來動態擴展java程序,因此一些類也會成為程序"不再引用"的類。當某個類變為不再被引用的類時,Java虛擬機可以卸載這個類(垃圾收集),從而使方法區占據的內存保持最小。

?

方法區針對具體的語言特性有幾種信息是存儲在方法區內的:

類型信息】 --對每個裝載的類型,虛擬機都會在方法區中存儲以下類型信息

?? ?這個類型的完全限定名(java.lang.String格式)

?? ?這個類型的直接超類的全限定名(除非uzhege類型時java.lang.Object,它沒有超類)

?? ?這個類型是類類型還是接口類型

?? ?這個類型的訪問修飾符(public、abstract或final的某個子集)

?? ?任何直接超接口的全限定名的有序列表

?

?在Java class文件和虛擬機中,類型名總是以全限定名出現。在java源代碼中,全限定名由類所屬包的名稱加上一個“.”,再加上類名組成。例如,類Object 的所屬包為java.lang,那她的全限定名應該是?java.lang.Object,但是在class文件里,所有的“.”都被斜杠“/”替換,這樣就成為java/lang/Object。至于全限定名在方法區中的表示,則因不同的設計者有不同的選擇而不同,可以用任何形式和數據結構來表示。

?

除了上面列出的基本類型信息外,虛擬機還得為每個被裝載的類型存儲以下信息:

【該類型的常量池】

【字段信息】

【方法信息】

【除了常量意外的所有類(靜態)變量】

【一個到ClassLoader的引用】

【一個到Class類的引用】

?

?【常量池

虛擬機必須為每一個被裝載的類型維護一個常量池。常量池就是該類型所用常量的一個有序集合,包括直接常量(string,integer和floating point常量)和對其他類型、字段方法符號引用。池中的數據項就像數組一樣是通過索引訪問的。因為常量池存儲了相應類型所用到的所有類型、字段和方法的符號引用,所以它在java程序的動態連接中起著核心的作用。

?

字段信息

對于類型中聲明的沒一個字段,方法區中必須保存下面的信息。除此之外,這些字段在類或者接口中的聲明順序也必須保存。下面是字段信息的清單:

字段名

字段的類型

字段的修飾符(public、private、protected、static、final、volatile、transient的某個子集)

?

?

方法信息

對于類型中聲明的每一個方法,方法區中必須保存下面的信息。和字段一樣,這些方法法在類或者接口中的聲明順序也必須保存。下面試方法信息的清單:

方法名

方法的返回類型(或void)

方法參數的數量和類型(按按聲明順序)

方法的修飾符(public、private、protected、static、final、synchronized、native、abstract的某個子集)

?

除了上面的清單中列出的條目之外,如果某個方法不是抽象的和本地的,它還必須保存下面的信息:

方法的字節碼(bytecodes)

操作數棧和該方法的棧幀中的局部變量區的大小

異常表

?

類(靜態)變量

類變量是由所有類實例共享的,即使沒有任何類實例,它也可以被訪問。這些變量只與類有關---而非類的實例,因此他們總是作為類型信息的一部分二存儲在方法區。除了在類中聲明的編譯時常量外,虛擬機在使用某個類之前,必須在方法區中為這些類變量分配空間。

?

而編譯時常量(就是那些用final聲明以及用編譯時已知的值初始化的類變量)則和一般的類變量的處理方式不同,每個使用編譯時常量的類型都會復制它的所有常量到自己的常量池中,或嵌入到它的字節碼流中。作為 常量池或字節碼流的一部分,編譯時常量保存在方法區中,就和一般的類變量一樣。但是當一般的類變量做為聲明他們的類型的一部分數據面保存的時候,編譯時常量作為使用他們的類型的一部分而保存。

?

指向ClassLoader類的應用

每個類型被加載的時候,虛擬機必須跟蹤它是由啟動類裝載器還是由用戶自定義類裝載器裝載的。如果是用戶自定義類裝載器裝載的,那么虛擬機必須在類型信息中存儲對該裝載器的引用。這是作為方法表中的類型數據的一部分保存的。虛擬機會在動態連接期間使用這個信息。當某個類型引用另外一個類型的時候,虛擬機會請求裝載發起引用類型的類裝載器類裝載來裝載被引用的類型。這個動態連接的過程,對于虛擬機分離命名空間的范式也是至關重要的。為了能夠正確地執行動態連接以及維護多個命名空間,虛擬機需要在方法表中得知每個類都是由哪個類裝載器裝載的,

?

指向Class類的引用

對于每個被裝載的類型(不管是類還是接口),虛擬機都會相應地位它創建一個java.lang.Class類的實例,而且虛擬機還必須以某種方式吧這個實例和存儲在方法區中的數據關聯起來。

?

?

方法表

為了盡可能提高訪問效率,設計者必須仔細設計存儲在方法區中的類型信息的數據結構,因此,除了以上討論的原始類型信息,實現中還可能包括其他數據結構加快訪問原始數據的速度,比如方法表。虛擬機對每個裝載的非抽象類,都生成一個方法表,把它作為類信息的一部分保存在方法區。方法表是一個數組,他的元素是所有他的實例可能被調用的實例方法的直接引用,包括哪些從超類繼承過來的實例方法。(對于抽象類和接口,方法表沒有什么幫助,因為程序絕不會生成他們的實例)運行時可以通過方法表快速搜索在對象中調用的實例方法。

?

方法區使用示例

為了展示虛擬機如何使用方法區中的信息,我們舉個例子,看下面這個類

Java代碼??
  • class?Lava{??
  • ????private?int?speed?=?5;??
  • ??
  • ????void?flow(){??
  • ?????}??
  • }??
  • ??
  • ??
  • class?Volcano{??
  • ????public?void?main(String[]?args)?{??
  • ????????Lava?lava?=?new?Lava();??
  • ????????lava.flow();??
  • ????}??
  • }??
  • ? ? ?下面的段落描述了某個實現是如何執行Volcano程序中main()方法的字節碼中第一條指令的。不同的虛擬機實現可能會用完全不同的方法來操作,下面描述的只是其中一種可能,但是并不是僅有的一種,下面看一下Java虛擬機是如何執行Volcano程序中main()方法的第一條指令的。

    ?

    ?? ?要運行Volcano程序,首先得以某種“依賴于實現的”方式告訴虛擬機“Volcano”這個名字。之后虛擬機將找到并讀入相應的class文件“Volcano.class”,然后他會從導入的class文件里的而精致數據中提取類型信息并放到方法區中。通過執行保存在方法區中額字節碼,虛擬機開始執行main()方法,在執行時,他會一直持有指向當前類(Volcano類)的常量池(方法區中的一個數據結構)的指針。

    ?

    ?? ?注意,虛擬機開始執行Volcano類中main()方法的字節碼的時候,盡管Lava類還沒被裝載,但是和大多數(也許是所有)?? ?虛擬機實現一樣,他不會等到把程序中用到的所有類都裝載后才開始運行程序。恰好相反,他只需在需要是才裝載相應的類

    ?

    ?? ? main()的第一條指令告知虛擬機為列在常量池第一項的類分配足夠的內存。所以虛擬機使用指向Volcano常量池的指針找到第一項,發現他是一個堆Lava類的符號引用,然后他就檢查方法區,看Lava類是否已經被裝載了。

    ?

    ?? ??這個符號引用僅僅是一個給出了類Lava的全限定名“Lava”的字符串。為了能讓虛擬機盡可能快地從一個名稱找到類,設計者應當選擇最佳的數據結構和算法。這里可以采用各種方法,如散列表、搜索樹等等。同樣的算法可以以用于實現Class類的forName()方法,這個方法根據給定的全限定名返回Class引用。

    ?

    ?? ?當虛擬機發現還沒有裝載過名為“Lava”的類時,他就開始查找并裝載文件“Lava.class”,并把從讀入的二進制數據中提取的類型信息放在方法區中。

    ?

    ?? ?緊接著,虛擬機以一個直接指向方法區Lava類數據的指針類替換常量池第一項(就是那個字符串“Lava”)----以后就可以用這個指針來快速訪問Lava類了。這個替換過程稱為常量池解析即把常量池中的符號引用替換為直接引用這是通過在方法區中搜索被引用的元素實現的,在這期間可能又需要裝載其他類。在這里,我們替換掉符號引用的“直接引用”是一個本地指針。

    ?

    ?? ? 終于,虛擬機轉變為一個新的Lava對象分配內存。此時,它又需要方法區中的信息。還記得剛剛放到Volcano類常量池第一項的指針嗎?現在虛擬機用它來訪問Lava類型信息(此前剛放到方法區中的),找到其中記錄的這樣一個信息:一個Lava對象需要分配多少堆空間。

    ?

    ?? ? Java虛擬機總能夠通過存儲于方法區的類型信息來實現一個對象需要的內存,但是,某一個特定對象事實上需要多少內存,是跟特定實現相關的。對象在虛擬機內部的表示由實現的設計者來決定的。

    ?

    ?? ? 當java虛擬機確定了一個Lava對象的大小后,它就在堆上分配這么大的空間,并把這個對象實例的變量speed初始化為默認初始值0.假如Lava類的超類Object也有實例變量,這也會在此時被初始化為相應的默認值。

    ?

    ?? ? 當把新生成的Lava對象的引用壓到棧中,main()方法的第一條指令也完成了。接下來的指令通過這個引用調用Java代碼(改代碼把speed變量初始化為爭取的初始值5)。另外一條指令將用這個引用調用Lava對 象引用的flow()方法。

    ??

    native method library(本地方法)

    就目前的理解就是jni的調用




    總結

    以上是生活随笔為你收集整理的Java虚拟机是什么的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。