本文目錄一覽:
你知道java的運行原理是什麼嗎
Java這一語言的執行過程也遵循這樣的過程:源代碼—機器碼。 但是,從源代碼到機器碼之間,究竟經過什麼樣的過程,則是Java獨一無二的了。寬泛地講,Java源代碼(.java)經過java編譯器(javac.exe)編譯之後,並沒有直接轉化為機器碼,而是轉化成一種中間格式,成為位元組碼(.class),位元組碼再經過java虛擬機轉化成特定CPU架構的機器碼。也正是因為這一中間物,java才有所謂的跨平台。在windows平台上編譯好的位元組碼,copy到linux平台後,經過為linux而設計的Java虛擬機解釋後即可執行。跨平台這一特徵,是通過位元組碼和JVM來實現的。
因此,想搞清楚java程序到底是如何運行的,重點在於弄明白位元組碼是如何被轉化成跟CPU架構相關的機器碼然後被執行的。也就是要理解JVM到底是如何工作的。在了解JVM之前,我們再跳出來一下,先看看什麼是虛擬機。所謂虛擬機,我是這麼理解的:用軟體的方式模擬出跟硬體類似的環境,比如說寄存器、存儲器等等。當然,所有最終的工作還是由原來的CPU來完成。比如說VirtualBox這個虛擬機產品,它其實就是一個應用程序,用某種編程語言編寫的應用程序。當運行這個應用程序時,它會要求操作系統給它獨立施展手腳的空間:給我一些內存,給我一定的CPU時間片,然後不用管我了。你可能會問,寄存器是硬體啊,它怎麼能劃分啊,難道是時間劃分?不是的,像內存這樣的硬體,可以給虛擬機一塊獨立的內存塊,但是寄存器之後的,則需要用「模擬模擬」的方式來模擬。OK,回到Java虛擬機。到底什麼是Java虛擬機,很難有一個十分明確的定義,狹窄一點說,它就是一個應用程序,大部分用C++編寫的。寬泛地說,它就是執行位元組碼的一整個環境。
java虛擬機工作原理?
從宏觀上介紹一下Java虛擬機的工作原理。從最初編寫的Java源文件(.java文件)是如何一步步執行的,如下圖所示,首先Java源文件經過前端編譯器(javac或ECJ)將.java文件編譯為Java位元組碼文件,然後JRE載入Java位元組碼文件,載入系統分配給JVM的內存區,然後執行引擎解釋或編譯類文件,再由即時編譯器將位元組碼轉化為機器碼。主要介紹下圖中的類載入器和運行時數據區兩個部分。
(1)類載入指將類的位元組碼文件(.class)中的二進位數據讀入內存,將其放在運行時數據區的方法區內,然後在堆上創建java.lang.Class對象,封裝類在方法區內的數據結構。類載入的最終產品是位於堆中的類對象,類對象封裝了類在方法區內的數據結構,並且向JAVA程序提供了訪問方法區內數據結構的介面。如下是類載入器的層次關係圖。
啟動類載入器(BootstrapClassLoader):在JVM運行時被創建,負責載入存放在JDK安裝目錄下的jre\lib的類文件,或者被-Xbootclasspath參數指定的路徑中,並且能被虛擬機識別的類庫(如rt.jar,所有的java.*開頭的類均被Bootstrap ClassLoader載入)。啟動類無法被JAVA程序直接引用。
擴展類載入器(Extension ClassLoader):該類載入器負責載入JDK安裝目錄下的\jre\lib\ext的類,或者由java.ext.dirs系統變數指定路徑中的所有類庫,開發者也可以直接使用擴展類載入器。
應用程序類載入器(AppClassLoader):負責載入用戶類路徑(Classpath)所指定的類,開發者可以直接使用該類載入器,如果應用程序中沒有定義過自己的類載入器,該類載入器為默認的類載入器。
用戶自定義類載入器(User ClassLoader):JVM自帶的類載入器是從本地文件系統載入標準的java class文件,而自定義的類載入器可以做到在執行非置信代碼之前,自動驗證數字簽名,動態地創建符合用戶特定需要的定製化構建類,從特定的場所(資料庫、網路中)取得java class。
注意如上的類載入器並不是通過繼承的方式實現的,而是通過組合的方式實現的。而JAVA虛擬機的載入模式是一種委派模式,如上圖中的1-7步所示。下層的載入器能夠看到上層載入器中的類,反之則不行。類載入器可以載入類但是不能卸載類。說了一大堆,還是感覺需要拿點代碼說事。
首先先定義自己的類載入器MyClassLoader,繼承自ClassLoader,並覆蓋了父類的findClass(String name)方法,如下:
利用定義的類載入器載入指定的位元組碼文件,如通過MyClassLoader載入C:\\Users\\Administrator\\下的Test.class位元組碼文件,代碼如下所示:
(2)運行時數據區
位元組碼的載入第一步,其後分別是認證、準備、解析、初始化,那麼這些步驟又具體做了哪些工作,如下圖所示:
(3)如下將介紹運行時數據區,主要分為方法區、Java堆、虛擬機棧、本地方法棧、程序計數器。其中方法區和Java堆一樣,是各個線程共享的內存區域,而虛擬機棧、本地方法棧、程序計數器是線程私有的內存區。
Java堆:Java堆是Java虛擬機所管理的內存中最大的一塊,被進程的所有線程共享,在虛擬機啟動時被創建。該區域的唯一目的就是存放對象實例,幾乎所有的對象實例都在這裡分配內存,隨著JIT編譯器的發展與逃逸分支技術逐漸成熟,棧上分配、標量替換等優化技術使得對象在堆上的分配內存變得不是那麼「絕對」。Java堆是垃圾收集器管理的主要區域。由於現在的收集器基本都採用分代收集演算法,所以Java堆中還可以分為老年代和新生代(Eden、From Survivor、To Survivor)。根據Java虛擬機規範,Java堆可以處於物理上不連續的內存空間,只要邏輯上連續即可。該區域的大小可以通過-Xmx和-Xms參數來擴展,如果堆中沒有內存完成實例分配,並且堆也無法擴展,將會拋出OutOfMemoryError異常。
方法區:用於存儲被Java虛擬機載入的類信息、常量、靜態變數、即時編譯器編譯後的代碼等數據。不同於Java堆的是,Java虛擬機規範對方法區的限制非常寬鬆,可以選擇不實現垃圾收集。但並非數據進入了方法區就「永久」存在了,這區域內存回收目標主要是針對常量池的回收和對類型的卸載。如果該區域內存不足也會拋出OutOfMemoryError異常。
常量池:這個名詞可能大家也經常見,是方法區的一部分。Class文件除了有類的版本、欄位、方法、介面等描述信息外,還有一項信息就是常量池,用於存放編譯期生成的各種字面量和符號引用。Java虛擬機運行期間,也可能將新的常量放入常量池(如String類的intern()方法)。
虛擬機棧:線程私有,生命周期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每個方法在執行時都會創建一個棧幀用於存儲局部變數表、操作數棧、動態鏈接、方法出口等信息。每個方法從調用直至執行完成的過程,就對應著一個棧幀在虛擬機棧中入棧到出棧的過程。如果請求的站深度大於虛擬機所允許的深度,將拋出StackOverflowError異常,虛擬機棧在動態擴展時如果無法申請到足夠的內存,就會拋出OutOfMemoryError異常。
過最簡單的一段代碼解釋一下,程序在運行時數據區個部分的變化情況。
(4)通過編譯器將Test.java文件編譯為Test.class,利用javap -verbose Test.class對編譯後的位元組碼進行分析,如下圖所示:
(5)看看運行時數據區的變化:
java是什麼東西?
Java說白了就是一門語言,像我們平時學校里學的英語,或者其他外語一樣,是和其他人交流的工具,讓別人知道你要表達什麼,只不過Java語言是面向計算機的,人與機器交流,讓計算機懂得我們所要表達的,從而讓計算機運行出我們想要的結果。
java是什麼東西
簡述Java程序從編寫到運行的基本步驟,並說明Java的基本工作原理
Java編譯原理:
Java 虛擬機(JVM)是可運行Java 代碼的假想計算機。只要根據JVM規格描述將解釋器移植到特定的計算機上,就能保證經過編譯的任何Java代碼能夠在該系統上運行。
一.Java源文件的編譯、下載 、解釋和執行
Java應用程序的開發周期包括編譯、下載 、解釋和執行幾個部分。Java編譯程序將Java源程序翻譯為JVM可執行代碼?位元組碼。這一編譯過程同C/C++ 的編譯有些不同。當C編譯器編譯生成一個對象的代碼時,該代碼是為在某一特定硬體平台運行而產生的。因此,在編譯過程中,編譯程序通過查表將所有對符號的引用轉換為特定的內存偏移量,以保證程序運行。Java編譯器卻不將對變數和方法的引用編譯為數值引用,也不確定程序執行過程中的內存布局,而是將這些符號引用信息保留在位元組碼中,由解釋器在運行過程中創立內存布局,然後再通過查表來確定一個方法所在的地址。這樣就有效的保證了Java的可移植性和安全 性。
運行JVM位元組碼的工作是由解釋器來完成的。解釋執行過程分三部進行:代碼的裝入、代碼的校驗和代碼的執行。裝入代碼的工作由”類裝載器”(class loader)完成。類裝載器負責裝入運行一個程序需要的所有代碼,這也包括程序代碼中的類所繼承的類和被其調用的類。當類裝載器裝入一個類時,該類被放在自己的名字空間中。除了通過符號引用自己名字空間以外的類,類之間沒有其他辦法可以影響其他類。在本台計算機上的所有類都在同一地址空間內,而所有從外部引進的類,都有一個自己獨立的名字空間。這使得本地類通過共享相同的名字空間獲得較高的運行效率,同時又保證它們與從外部引進的類不會相互影響。當裝入了運行程序需要的所有類後,解釋器便可確定整個可執行程序的內存布局。解釋器為符號引用同特定的地址空間建立對應關係及查詢表。通過在這一階段確定代碼的內存布局,Java很好地解決了由超類改變而使子類崩潰的問題,同時也防止了代碼對地址的非法訪問。
隨後,被裝入的代碼由位元組碼校驗器進行檢查。校驗器可發現操作數棧溢出,非法數據類型轉化等多種錯誤。通過校驗後,代碼便開始執行了。
Java位元組碼的執行有兩種方式:
1.即時編譯方式:解釋器先將位元組碼編譯成機器碼,然後再執行該機器碼。
2.解釋執行方式:解釋器通過每次解釋並執行一小段代碼來完成Java位元組碼程 序的所有操作。
通常採用的是第二種方法。由於JVM規格描述具有足夠的靈活性,這使得將位元組碼翻譯為機器代碼的工作
具有較高的效率。對於那些對運行速度要求較高的應用程序,解釋器可將Java位元組碼即時編譯為機器碼,從而很好地保證了Java代碼的可移植性和高性能。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/151542.html