JVM啟動工作原理

1. JVM體系結構

(1)類加載器(`ClassLoader`)(用來裝載`.class`文件)

(2)執行引擎(執行字節碼,或者執行本地方法)

(3)運行時數據區(方法區、堆、java棧、本地方法棧、PC寄存器)

2. JVM的生命周期

1.JVM實例對應了一個獨立運行的java程序,它是進程級別;

a)啟動。啟動一個java程序時,一個JVM實例就產生了,任何一個擁有`public static void main(String
[] args)`方法的class都可以作為JVM實例運行的起點

b)運行。`main()`作為該程序的初始線程的起點,任何其他線程均由該線程啟動。JVM內部有兩種線程:守護線
程和非守護線程,`main()`屬于非守護線程守護線程通常由JVM自己使用,java程序也可以標明自己創建的線程
是守護線程

c)消亡。當程序中的所有非守護線程都終止時,JVM才退出;若安全管理器允許,程序也可以使用`Runtime`類
或者`System.exit()`來退出

2.JVM執行引擎實例則對應了屬于用戶運行程序的線程,它是線程級別的;

3. JVM啟動

JVM工作原理和特點主要是指操作系統裝入JVM,是通過JDK中java.exe來完成,通過下面4步來完成JVM環境.

1.創建`JVM`裝載環境和配置

2.裝載`JVM.dll`

3.初始化`JVM.dll`并掛界到`JNIENV`(`JNI`調用接口)實例

4.調用`JNIENV`實例裝載并處理`class`類

3.1 啟動代碼分析

main函數在openjdk\jdk\src\share\bin\main.c文件中。簡單流程分析如下:

1.SelectVersion->LocateJRE,定位jre的位置。因為在不同的操作系統上定位jre的方式不同,相關代碼就
和平臺相關了,windows相關的一些代碼在`openjdk\jdk\src\windows`下,而`linux`和`solaris`相關
代碼在`openjdk\jdk\src\solaris`下。這部分調用到的代碼都在`{os}\bin\java_md.c`中。簡單的說,
windows中,LocateJRE要通過查找注冊表來定位jre的位置,而Linux下可能需要讀取環境變量等。

2.CreateExecutionEnvironment->GetJVMPath得到jvm的路徑,其實就是找到相應的動態鏈接
庫,具體到linux上,就是`libjvm.so`。

3.LoadJavaVM,linux上是加載'libjvm.so',windows上是加載`jvm.dll`,導
出`JNI_CreateJavaVM`、`JNI_GetDefaultJavaVMInitArgs`等函數。

4.獲取classpath。

5.ContinueInNewThread(&ifn,argc,argv,jarfile,classname,ret);在一個新線程中啟動jvm。
ContinueInNewThread的功能是:調用`GetDefaultJavaJVMInitArgs`(其實就
調用`JNI_GetDefaultJavaVMInitArgs`)獲取虛擬機初始化參數,設定線程棧的大小,
創建java程序需要的各項參數。然后調用下面函數 `ContinueInNewThread0(JavaMain, 
threadStackSize, (void*)&args);` ;因為不同操作系統創建線程的方式不同,所以又進
入os相關的代碼,`{os}\bin\java_md.c`中的`int ContinueInNewThread0(JNICALL 
*continuation)(void *), jlong stack_size,void *args)`函數。
    
    閱讀其源碼,可知linux上是通過`pthread_create`創建線程,Solaris通過`thr_create`創建線程,
    而`windows`則通過`_beginthreadex`創建線程。
    
    在新線程中調用JavaMain函數,即openjdk\jdk\src\share\bin\main.c中的 `int JNICALL 
    JavaMain(void *_args)`,它負責加載要運行的的java class,并調用class的main方法。
    
    處理步驟是:
    
    1).InitalizeJVM->CreateJavaVM(即通過JNI調用JNI_CreateJavaVM),創建jvm。
    2).LoadMainClass加載main class,并確保main方法的簽名是正確的。 
    3).mainID = (*env)->GetStaticMethodID(env, mainClass, "main","([Ljava/lang/String;)V");通過JNI得到main方法的method信息。 
    4).mainArgs = NewPlatformStringArray(env, argv, argc);為main方法準備參數數組。 
    5).(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);通過JNI調用main方法。 
    6).ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;處理異常 
    7).DetachCurrentThread 
    8).DestroyJavaVM 銷毀JVM

下面以windows的實現進行分析:

首先查找jre路徑,Java通過GetApplicationHome api來獲得當前的java.exe絕對路徑(例如我電腦上的e:\program \java\jdk\bin\java.exe),那么它會截取到絕對路徑e:\program\java\jdk,判斷e:\program\java\jdk\jvm.dll
文件是否存在,如果存在就把e:\program\java\jdk,作為jre路徑;如果不存在則判斷e:\program\java\jdk\jre\jvm.dll
是否存在,如果存在則將e:\program\java\jdk\jre作為jre路徑。如果不存在調用GetPublicJREHomeHKEY_LOCAL _MACHINE\Software\JavaSoft\Java Runtime Environment\"當前JRE版本號"\JavaHome的路徑作為jre路徑。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 轉載blog.csdn.net/ning109314/article/details/10411495/ JVM工...
    forever_smile閱讀 5,402評論 1 56
  • 1.創建文件夾 !/bin/sh mkdir -m 777 "%%1" 2.創建文件 !/bin/sh touch...
    BigJeffWang閱讀 10,186評論 3 53
  • 今天在Windows下安裝JDK8時遇到以下問題,原本機子上安裝了JDK7,正常步驟安裝JDK8以后 java -...
    言西棗閱讀 6,480評論 0 4
  • 20歲看似很陽光很充滿精力的年紀,可是你有沒有在每天晚上躺在舒服的床上,有沒有反思自己,反思這一天你是否過的有意...
    十一其實不二閱讀 151評論 0 3
  • 有時候,你選擇與某人保持距離,不是因為不在乎,而是因為你清楚的知道她不屬于你,人生遇到的每個人,出場順序真的很重要...
    白系閱讀 182評論 0 0