自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

了解JVM的結構,好在面試時吹牛

云計算 虛擬化
在一個線程執(zhí)行的任何時刻,都只會有一個幀是處于激活的。這個幀被稱為當前幀,與之對應的方法被稱為當前方法,方法所在的類被稱為當前類,此時用到的本地變量數(shù)組和操作數(shù)棧也都是當前幀的。

[[286442]]

jvm包括兩種數(shù)據(jù)類型,基本類型和引用類型。

基本類型包括,數(shù)值類型,boolean類型,和returnAddress類型。

數(shù)值類型包括,整型,浮點型,和char類型。

boolean類型同樣只有true和false。

returnAddress類型是一個指針,指向jvm指令的操作碼,在Java中沒有與之對應的類型。

boolean類型的操作會被轉化為int類型的操作進行,boolean數(shù)組會當成byte數(shù)組去操作。1表示true,0表示false。

引用類型包括三種,類類型,數(shù)組類型,和接口類型。

它們的值是動態(tài)創(chuàng)建的類實例,數(shù)組,或實現(xiàn)接口的類實例。

數(shù)組有component類型和element類型,component類型就是數(shù)組去掉最外層維度后剩下的類型,可能還是一個數(shù)組類型(對于多維數(shù)組)。

element類型就是數(shù)組里面存儲的最小數(shù)據(jù)的類型,它必須是一個基本類型,類類型,或接口類型。

對于一維數(shù)組的話,component類型和element類型是相同的。

引用類型還有一個特殊值,就是null,表示沒有引用任何對象。

運行時公有數(shù)據(jù)區(qū)

jvm有一個堆,在所有jvm線程間共享,堆是一個運行時數(shù)據(jù)區(qū)域,所有為類實例和數(shù)組分配的內存都來自于它。

堆在jvm啟動時創(chuàng)建,堆中對象不用顯式釋放,gc會幫我們釋放并回收內存。

方法區(qū)

jvm有一個方法區(qū),在所有jvm線程間共享,它存儲每一個類的結構。

像運行時常量池,字段和方法數(shù)據(jù),方法和構造函數(shù)的代碼,還有特殊的方法用于類和實例的初始化,以及接口的初始化。

方法區(qū)在jvm啟動時創(chuàng)建,雖然方法區(qū)在邏輯上是堆的一部分。

但簡單實現(xiàn)時可以選擇不進行gc和壓縮,本規(guī)范沒有強制要求方法區(qū)的位置,也沒有要求管理已編譯代碼的策略。

運行時常量池

運行時常量池就是類或接口的字節(jié)碼文件里的常量池的運行時表示形式,它包含幾種常量。

如在編譯時就已經(jīng)知道的數(shù)字字面量值,和必須在運行時解析的方法和字段的引用,運行時常量池的功能類似于傳統(tǒng)語言的符號表,不過它包含的數(shù)據(jù)會更加寬泛。

運行時常量池分配在jvm的方法區(qū),類或接口的運行時常量池在類或接口被jvm創(chuàng)建時才會構建。

運行時私有數(shù)據(jù)區(qū)

pc寄存器

jvm支持一次運行多個線程,每個線程都有自己的pc寄存器,任何時候一個線程只能運行一個方法的代碼。

如果方法不是native的,pc寄存器包含當前正在被執(zhí)行的jvm指令地址,如果方法是native的,pc寄存器的值是未定義的。

jvm棧

每一個jvm線程都有一個私有的jvm棧,隨著線程的創(chuàng)建而創(chuàng)建,棧中存儲的是幀。

jvm棧和傳統(tǒng)語言如C的棧相似,保存局部變量和部分計算結果,參與方法的調用和返回。jvm棧主要用于幀的出棧和入棧,除此之外沒有其它操作,

幀可能是在堆上分配的,所以jvm棧使用的內存不必是連續(xù)的。

native方法棧

native方法不是用Java語言寫的,為了支持它需要使用傳統(tǒng)棧,如C語言棧。不過jvm不能加載native方法,所以也不需要提供native方法需要的棧。

每次當一個方法被調用時一個新的幀會被創(chuàng)建。當方法調用完成時,與之對應的幀會被銷毀,無論是正常完成還是拋異常結束。

所以幀是方法調用的具體體現(xiàn)形式,或稱方法調用是以幀的形式進行的。幀用來存儲數(shù)據(jù)和部分計算結果,和執(zhí)行動態(tài)鏈接,方法返回值,分發(fā)異常。

幀分配在創(chuàng)建幀的線程的jvm棧上,每一個幀都有自己的本地變量數(shù)組,自己的操作數(shù)據(jù)棧,和一個對當前方法所在類的運行時常量池的引用。

本地變量數(shù)組和操作數(shù)棧的大小在編譯時就確定了,它們隨著和幀關聯(lián)的方法編譯后的代碼一起被提供,因此幀這種數(shù)據(jù)結構的大小只依賴于jvm的實現(xiàn),這些結構所需的內存可以在方法調用時同時被分配。

在一個線程執(zhí)行的任何時刻,都只會有一個幀是處于激活的。這個幀被稱為當前幀,與之對應的方法被稱為當前方法,方法所在的類被稱為當前類,此時用到的本地變量數(shù)組和操作數(shù)棧也都是當前幀的。

一個幀將不在繼續(xù)是當前幀,如果它的方法調用了另一個方法,或者它的方法結束了。

當一個方法被調用,一個新的幀被創(chuàng)建,當執(zhí)行控制由原來的方法傳遞到新的方法時,這個新的幀變?yōu)楫斍皫?/p>

當方法返回時,當前幀把方法執(zhí)行的結果傳回到上一幀,當上一幀被激活的同時當前幀會被丟棄。

本地變量數(shù)組

每一幀都包含一個變量數(shù)組,就是都熟知的本地變量存儲的地方。這個本地變量數(shù)組的長度在編譯時確定,隨著編譯后的方法代碼一起提供。

通常一個本地變量(的位置)能夠存儲一個類型的值,但是long和double類型卻需要兩個本地變量(的位置)才能存一個值。

本地變量按索引尋址,第一個本地變量的索引是0。long和double需要消耗兩個連續(xù)的索引,但卻是按照較小的這個索引尋址的。不能按照較大的那個索引去讀數(shù)據(jù),但是可以寫入,當然這樣將使本地變量內容錯亂。

在方法被調用時,jvm使用本地變量來接收傳遞進來的參數(shù)值。在類(靜態(tài))方法調用時,所有參數(shù)被傳入從索引0開始的連貫的本地變量數(shù)組里。

在實例(非靜態(tài))方法調用時,索引0處總是傳入正在其上執(zhí)行方法調用的那個對象的引用,(就是Java中的this了),所有參數(shù)被傳入從1開始的連貫的本地變量數(shù)組里。

操作數(shù)棧

每個幀包含一個后進先出的棧,用于存儲正在執(zhí)行的jvm指令的操作數(shù),就是都熟知的操作數(shù)棧,這個棧的最大深度在編譯時就已確定,隨著編譯后的方法代碼一起提供。

當幀被創(chuàng)建時,操作數(shù)棧是空的,jvm提供一些指令用于加載常量值,本地變量值,字段值到操作數(shù)棧上,另一些jvm指令采用操作數(shù)棧上的操作數(shù)進行操作,并把結果放回到操作數(shù)棧上。

操作數(shù)棧也用于準備將要傳遞給方法調用的參數(shù)和接收方法調用返回的結果。

long和double類型的值占用兩個單位的棧深度,其它類型的值占用一個單位的棧深度。

動態(tài)鏈接

每一個幀都包含了對當前方法所屬類型的運行時常量池的引用。目的是為了支持方法代碼的動態(tài)鏈接。class文件中描述一個方法引用被調用的方法和被訪問的變量的代碼,是采用符號引用的形式實現(xiàn)的。

符號引用的形式可以粗略的認為是字符串的形式,就是用字符串標明需要調用哪個類的哪個方法或訪問哪個字段或變量。就像符號引用這個名字一樣,這些僅僅是符號,是拿不到具體值的,所以必須要進行轉換。

動態(tài)鏈接就是把這些符號方法引用轉換為具體的方法引用,在必要時加載類來解析尚未明確的符號,把符號變量的訪問轉換為這些變量運行時所在存儲結構的適合的偏移量(索引)。這樣的方式又稱為后期綁定。

方法調用

一個方法調用正常完成(即沒有拋異常)時,會根據(jù)所返回的值的類型執(zhí)行一個適合的return指令,當前幀會去恢復調用者的狀態(tài),包括它的本地變量和操作數(shù)棧,使調用者的程序計數(shù)器適合的遞增來跳過剛剛的那個方法調用指令。

返回值會被放到調用者幀的操作數(shù)棧上,然后繼續(xù)執(zhí)行調用者方法的幀。

一個方法在調用時拋出了異常,且這個異常沒有在這個方法內被捕獲處理,將會導致這個方法調用的突然結束,這種情況下永遠不會向方法的調用者返回一個值。

特殊方法

站在jvm的級別,每一個用Java寫的構造函數(shù)都以一個實例初始化方法出現(xiàn),且都是特殊的名字,就是,這個名字是編譯器提供的。

實例初始化方法只能在jvm內部使用invokespecial這個指令調用,且只能在尚未初始化的類實例上調用。

一個類或接口最多可以有一個類或接口初始化方法,通過調用這個方法被初始化。類或接口的初始化方法也有特殊的名字,就是,該方法沒有參數(shù),且返回值是void。

方法名稱也是由編譯器提供的,從Java7開始,在字節(jié)碼中這個方法必須被標記為靜態(tài)的才行。

這個初始化方法是被jvm隱式調用的,它們絕對不會直接被用任何jvm指令調用,僅作為類初始化進程的一部分被間接的調用。

Java類庫

jvm必須為Java類庫的實現(xiàn)提供足夠的支持。一些類庫中的類如果沒有jvm協(xié)助是無法實現(xiàn)的。

反射,就是在運行時獲取某個類的類型相關信息,如它的字段信息,方法信息,構造函數(shù)信息,父類信息,實現(xiàn)的接口信息。

這些信息都必須是把一個類加載完之后才可以知道的,只有jvm才可以加載類。如java.lang.reflect這個包下的類和Class這個類。

在Java中加載一個類或接口用類加載器,即ClassLoader,背后還是委托給jvm來實現(xiàn)的。

鏈接和初始化一個類或接口。

安全,如java.security包下的類,還有其它類像SecurityManager。

多線程,如線程這個類Thread。

弱引用,像java.lang.ref包下的類。

公有設計,私有實現(xiàn)

以上內容只是jvm的一個“相對寬泛”的規(guī)范,它并不是實現(xiàn)方案,也不是實現(xiàn)細節(jié)。

實現(xiàn)者可以根據(jù)自身的需要來實現(xiàn)jvm,如運行在后端服務器上的jvm和運行在移動設備上的jvm肯定側重點有所不同。

從事Java的人都知道,事實上jvm是有較多的實現(xiàn)版本。

由于jvm是處在Java語言和操作系統(tǒng)之間的,所以它要向上提供對Java的支持,向下與操作系統(tǒng)良好交互。

寫在最后

高級語言(Java,C#)中的很多操作如文件操作,網(wǎng)絡操作,內存操作,線程操作,I/O操作等,都不是高級語言自身能夠實現(xiàn)的。

也不是它們的虛擬機(JVM,CLR)能夠實現(xiàn)的,實際最終是由操作系統(tǒng)實現(xiàn)的,因為這些都是系統(tǒng)資源,只有操作系統(tǒng)才有權限訪問。

如果你用Java或C#代碼創(chuàng)建了一個文件,千萬不要以為是Java或C#創(chuàng)建了這個文件,它們只是層層向下調用了操作系統(tǒng)的API,然后到文件系統(tǒng)API,最后可能到磁盤驅動程序。

由此可以看出,要想設計一門語言,不單單是關鍵字、語法、編譯器,類庫,虛擬機這些,還要深度了解操作系統(tǒng),甚至是硬件,如CPU架構和CPU指令集等。

所以,和語言相關的事情,每一項都是異常的繁瑣復雜,都需要投入大量的人力、財力、時間去研究,最后即使研究成功了,可能沒有生態(tài),沒人使用,自然也無法賺錢。

因此,國人現(xiàn)在還沒有一門屬于自己的真正語言。

責任編輯:武曉燕 來源: 編程新說
相關推薦

2010-08-10 16:21:48

面試薪資

2012-08-20 14:09:29

面試

2010-08-09 16:30:53

面試

2022-01-10 06:53:00

JVM 面試Java

2010-11-09 10:24:46

面試

2009-02-27 10:30:09

面試聯(lián)想智力

2010-09-27 09:31:42

JVM內存結構

2022-04-30 08:09:37

面試開發(fā)閱讀源碼

2010-08-04 14:11:58

面試木訥

2012-12-28 15:53:53

面試應屆畢業(yè)生

2010-04-20 14:59:56

面試

2010-07-20 15:52:01

面試

2021-06-21 07:44:07

程序員面試職場

2014-08-13 09:47:17

面試

2020-10-26 08:55:52

Redis單線程模型

2012-08-23 09:44:32

面試面試題算法

2010-06-09 11:20:53

求職者面試

2011-03-01 09:36:26

面試算法解題思路

2014-08-14 10:19:01

程序員

2018-06-27 13:10:22

程序員面試易犯錯誤
點贊
收藏

51CTO技術棧公眾號