利用Java編寫一個Java虛擬機
github 項目鏈接
https://github.com/FranzHaidnor/haidnorJVM
haidnorJVM
使用 Java17 編寫的 Java 虛擬機
意義
- 紙上得來終覺淺,絕知此事要躬行。只學習 JVM 機制和理論,很多時候任然覺得缺乏那種大徹大悟之感
- 使用簡單的方式實現 JVM,用于學習理解 JVM 運行原理
主要技術選型
實現功能
- 實現了 99% 的 JVM 字節(jié)碼指令。參照 JVM 字節(jié)碼規(guī)范實現 The Java Virtual Machine Instruction Set
- 支持算數運算符 (
+
,-
,*
,^
,%
,++
,--
) - 支持關系運算符 (
==
,!=
,>
,<
,>=
,<=
) - 支持位運算符 (
&
,|
,^
,~
,<<
,>>
,>>>
) - 支持賦值運算符 (
=
,+=
,-=
,*=
,%=
,<<=
,>>=
,&=
,^=
,|=
) - 支持 instanceof 運算符
- 支持循環(huán)結構代碼 (
while
,do...while
,for
,foreach
) - 支持條件結構代碼 (
if
,if...else
,if...else if
) - 支出創(chuàng)建自定義類
- 支持創(chuàng)建對象、訪問對象
- 支持抽象類
- 支持多態(tài)繼承、接口
- 支持訪問靜態(tài)方法
- 支持訪問對象方法
- 支持 JDK 中自帶的 Java 類
- 支持反射
- 支持異常
- 枚舉 (開發(fā)中...)
- switch 語法 (開發(fā)中...)
- lambda 表達式 (開發(fā)中...)
局限性
不支持多線程
不支持多維數組
暫無雙親委派機制實現
無垃圾收集器實現。垃圾回收依靠宿主 JVM
快速體驗
你需要準備什么
- 集成開發(fā)環(huán)境 (IDE)。你可以選擇包括 IntelliJ IDEA、Visual Studio Code 或 Eclipse 等等
- JDK 17。并配置 JAVA_HOME
- JDK 8。haidnorJVM 的主要目標是運行 Java8 本版的字節(jié)碼文件。(但 haidnorJVM 沒有強制要求字節(jié)碼文件是 Java8 版本)
- Maven
配置 haidnorJVM
配置日志輸出級別
在 resources\simplelogger.properties
文件中修改日志輸出級別,一般使用 debug
、info
- 配置 info 級別將不會看到任何 haidnorJVM 內部運行信息
- 配置 debug 級別下運行將會非常友好的輸出 JVM 正在執(zhí)行的棧信息
public class Demo5 { public static void main(String[] args) { String str = method1("hello world"); method1(str); } public static String method1(String s) { return method2(s); } public static String method2(String s) { return method3(s); } public static String method3(String s) { System.out.println(s); return "你好 世界"; } }
每一個 匚
結構圖形,都表示一個 JVM 線程棧中的棧幀
配置 rt.jar 路徑
修改 haidnorJVM.properties
文件中的內容。配置 rt.jar 的絕對路徑,例如rt.jar=D:/Program Files/Java/jdk1.8.0_361/jre/lib/rt.jar
運行單元測試用例
在 IDE 中打開項目中 test 目錄下的 haidnor.jvm.test.TestJVM.java
文件。 這是 haidnorJVM 的主要測試類, 里面的測試方法可以解析加載運行 .class 字節(jié)碼文件。
public class TestJVM { /** * haidnorJVM 會加載 HelloWorld.java 在 target 目錄下的編譯后的字節(jié)碼文件,然后運行其中的 `main(String[] args)` 方法。 * 你可以使用打斷點的方式看到 haidnorJVM 是如何解釋運行 Java 字節(jié)碼的。 * 值得注意的是,這種方式編譯運行的字節(jié)碼文件是基于 java17 版本的。 */ @Test public void test() { runMainClass(HelloWorld.class); } }
運行 .class 文件
- 使用 maven 命令將 haidnorJVM 編譯打包,得到
haidnorJVM.jar
文件 - 編寫一個簡單的程序,例如以下代碼
public class HelloWorld { public static void main(String[] args) { System.out.println("HelloWorld"); } }
- 編譯代碼,得到 HelloWorld.class 文件 (推薦使用 JDK8 進行編譯)
- 使用 haidnorJVM 運行程序。執(zhí)行命令
java -jar haidnorJVM.jar -class R:\HelloWorld.class
。注意! 需要 class 文件的絕對路徑
運行 .jar 文件
- 使用 maven 命令將 haidnorJVM 編譯打包,得到
haidnorJVM.jar
文件 - 編寫一個 java 項目編譯打包成 .jar 文件,例如 demo.jar。要求 .jar 文件中的 META-INF/MANIFEST.MF 文件內有
Main-Class
屬性 (含有public static void main(String[] args)
方法的主類信息) - 使用 haidnorJVM 運行程序。執(zhí)行命令
java -jar haidnorJVM.jar -class R:\demo.jar
。注意! 需要 jar 文件的絕對路徑
存在的問題
由于 haidnorJVM 目前運行 JDK 自帶的類是使用反射解決的,因此 haidnorJVM 使用 JDK17 運行部分 JDK 自帶的類時會存在一些問題,例如運行以下代碼將會拋出異常
public class Demo { public static void main(String[] args) { List<Integer> list = List.of(1, 2, 3, 4, 5); list.add(6); } }
java.lang.reflect.InaccessibleObjectException: Unable to make public boolean java.util.ImmutableCollections$AbstractImmutableCollection.add(java.lang.Object) accessible: module java.base does not "opens java.util" to unnamed module @18769467 at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354) at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199) at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
它表示嘗試通過反射來訪問一個方法或字段,但該方法或字段的可訪問性限制導致無法訪問。
這個限制通常是由于 Java 模塊系統引起的。模塊系統允許將代碼劃分為獨立的模塊,并控制模塊之間的訪問權限。以上異常的原因是 module java.base does not "opens java.util" to unnamed module,也就是說 java.base 模塊沒有向未命名模塊開放 java.util 包
解決方法:啟動 haidnorJVM 時添加 JVM 參數 --add-opens java.base/java.util=ALL-UNNAMED
繞過訪問性限制
以上就是利用Java編寫一個Java虛擬機的詳細內容,更多關于Java虛擬機的資料請關注腳本之家其它相關文章!
相關文章
詳解Spring Cloud Stream使用延遲消息實現定時任務(RabbitMQ)
這篇文章主要介紹了詳解Spring Cloud Stream使用延遲消息實現定時任務(RabbitMQ),小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01Java16 JDK安裝并設置環(huán)境變量的方法步驟
突然想起自己大學剛接觸java的時候,要下載JDK和配置環(huán)境變量,那時候我上網找了很多教學,本文就詳細的介紹一下Java16 JDK安裝并設置環(huán)境變量,感興趣的可以了解一下2021-09-09