一個java文件是怎麼一步一步執行的

来源:https://www.cnblogs.com/dongguangming/archive/2020/05/09/12858832.html
-Advertisement-
Play Games

說點什麼呢,java比你想的要難 寫了多年java,發現好多人並不知道一個class文件怎麼被解析執行的,所以我也發表下看法 1. 編寫java源文件 ​ 2. 把java源文件編譯成.class位元組碼文件,JVM不認識源文件 ​ 3. JVM處理class文件 搞java開發,不得不提的就是JVM ...


 

說點什麼呢,java比你想的要難

寫了多年java,發現好多人並不知道一個class文件怎麼被解析執行的,所以我也發表下看法

1.  編寫java源文件


2.  把java源文件編譯成.class位元組碼文件,JVM不認識源文件


 3.  JVM處理class文件

搞java開發,不得不提的就是JVM了,JVM全稱是Java Virtual Machine(簡稱JVM,中文叫Java虛擬機,請務必記住JVM,看到不少人整天JVM的,都不知道它的全稱是什麼),java的宿主環境,可以認為JVM就是虛擬模擬出來的一臺電腦。簡單繪了一張圖,如下(一圖勝千言):


java之所以一次編寫,到處運行,就是因為虛擬機(虛擬虛擬,虛擬出來的電腦,一臺被托管的電腦)的緣故。

 

3.1 jvm處理class文件

 載入是指將java源文件編譯之後的class文件讀入到記憶體中,然後在堆區創建一個java.lang.Class對象,用於封裝類在方法區內的數據結構。類載入的最終目的是封裝類在方法區的數據結構,並向java程式員提供訪問方法區數據的介面。

類的生命周期一共分為5個階段,載入、連接、初始化、使用、卸載。


載入:類的載入過程主要完成3件事件,1.通過類的全限定名來獲取定義此類的二進位位元組流,2.將這個類位元組流代表的靜態存儲結構轉為方法區的運行時數據結構,3.在堆中生成一個代表此類的java.lang.Class對象,作為訪問方法區這些數據結構的入口。這個過程主要是類載入器完成的,如圖


 

從上圖我們就可以看出類載入器之間的父子關係和管轄範圍。

BootStrap是最頂層的類載入器,它是由C++編寫而成,並且已經內嵌到JVM中了,主要用來讀取Java的核心類庫JRE/lib/rt.jar

ExtensionClassLoader是是用來讀取Java的擴展類庫,讀取JRE/lib/ext/*.jar

AppClassLoader是用來讀取CLASSPATH指定的所有jar包或目錄的類文件

甚至可以自定義載入器

載入過程用到了很牛掰的雙親委派模型,它是這樣的一套機制:

"類載入器"載入類時,先判斷該類是否已經載入過了;

如果還未被載入,則首先委托其"類載入器"的"父類載入器"去載入該類,這是一個向上不斷搜索的過程,當類所有的"祖宗類載入器"(包括了bootstrap  classloader)都沒有載入到類,則回到發起者"類載入器"去載入,如果還載入不了,則拋出ClassNotFoundException.

請參考http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/ClassLoader.java

連接:這個過程分3個階段(校驗,準備,解析)完成。首先是校驗,此階段主要校驗class文件包含的信息是否符合jvm的規範。具體的校驗通過對文件格式,元數據,位元組碼,符號引用驗證來完成。然後是準備,此階段為類變數分配記憶體,並將其初始化為預設值。最後是解析,即把類型中的符號引用轉換成為直接引用。具體的解析有4種,1.類或介面的解析,2.欄位解析,3.類方法解析,4.介面方法解析。完成這3個階段就完成了類的連接。

初始化(很重要):即執行類的構造器方法的過程。有5種方法可以完成初始化:1.調用new方法,2.使用Class類的newInstance方法(反射機制),3.使用Constructor類的newInstance方法(反射機制),4.使用Clone方法創建對象,5.使用(反)序列化機制創建對象

碼農開發用new關鍵字創建對象,而框架(spring,mybatis等)特別喜歡用第2和3種方式創建對象,還記得我說的框架四要素嗎,其中有一要素就是反射機制

使用:完成類的初始化後,就可以對類進行實例化,在程式中進行使用了

卸載:當類被載入,連接和初始化後,它的生命周期就始了,當代表類的class對象不在被引用時,class對象就會結束生命周期,類在方法區內的數據就會被卸載。因此一個類何時結束生命,取決於代表它的class對象何時結束生命。

 

3.2  JVM的記憶體結構

Java程式在運行時,需要在記憶體中的分配空間。為了提高運算效率,就對數據進行了不同空間的劃分,因為每一片區域都有特定的處理數據方式和記憶體管理方式,如上圖,Java中的記憶體分配了5個區

 Method Area方法區

方法區是被所有線程共用,所有欄位和方法位元組碼,以及一些特殊方法如構造函數,介面代碼也在此定義。簡單說,所有定義的方法的信息都保存在該區域,此區域屬於共用區間。

靜態變數+常量+類信息+運行時常量池存在方法區中,實例變數存在堆記憶體中。

 Heap 堆:堆這塊區域是JVM中最大的,應用的對象和數據都是存在這個區域,這塊區域也是線程共用的,也是 gc 主要的回收區,一個 JVM 實例只存在一個堆類存,堆記憶體的大小是可以調節的。類載入器讀取了類文件後,需要把類、方法、常變數放到堆記憶體中,以方便執行器執行。


註jdk8永久代改為了metaspace元空間

Stack 棧:棧也叫棧記憶體,主管Java程式的運行,是線上程創建時創建,它的生命期是跟隨線程的生命期,線程結束棧記憶體也就釋放,對於棧來說不存在垃圾回收問題,只要線程一結束該棧就Over,生命周期和線程一致,是線程私有的, 基本類型的變數和對象的引用變數都是在函數的棧記憶體中分配。遵循“先進後出”/“後進先出”原則。

PC Register程式計數器

每個線程都有一個程式計算器,就是一個指針,指向方法區中的方法位元組碼(下一個將要執行的指令代碼),由執行引擎讀取下一條指令,是一個非常小的記憶體空間,幾乎可以忽略不記。

Native Method Stack本地方法棧

它的具體做法是Native Method Stack中登記native方法,在Execution Engine執行時載入native libraies。

 

暫且這麼多,以後接著補充。。。。。。

 

參考:

0. The Java® Language Specification(8)  https://docs.oracle.com/javase/specs/jls/se8/html/index.html

1. The Java® Virtual Machine Specification (8) https://docs.oracle.com/javase/specs/jvms/se8/html/index.html

我想於java碼農而言,沒有比這這兩個官方上千頁的規範更重要的了,看清楚了:一個是Java語言規範,一個是Java虛擬機規範



當然還有其他規範為了方便碼農開發

 

​ 

 

2. Advanced Java Bytecode Tutorial  https://www.jrebel.com/blog/java-bytecode-tutorial

3.  深入JVM:ClassLoader相關知識簡介   https://developer.51cto.com/art/201009/227269.htm

4. Java Class Loader  https://javapapers.com/core-java/java-class-loader/

5. Understanding the Java ClassLoader  https://www.ibm.com/developerworks/java/tutorials/j-classloader/j-classloader.html

6. Advanced Java Class Tutorial: A Guide to Class Reloading  https://www.toptal.com/java/java-wizardry-101-a-guide-to-java-class-reloading

7. 看完這篇文章你還敢說你懂JVM嗎? https://virtual.51cto.com/art/201901/591418.htm?mobile

8. JVM  internals  https://blog.jamesdbloom.com/JVMInternals.html#jvm_system_threads

9.  Difference between initializing a class and instantiating an object? 

https://stackoverflow.com/questions/15074083/difference-between-initializing-a-class-and-instantiating-an-object

10. class-loader-subsystem-jvm-internals  https://codepumpkin.com/class-loader-subsystem-jvm-internals/

 

參考書籍:

0.  Java編程思想  (第1,,2,5,8,14章節)


 

 1.  Virtual Machines


模仿一臺電腦


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...