執行Java,執行java檔案

來源:互聯網
上載者:User

執行Java,執行java檔案


最近在閱讀JVM源碼,把一些心得寫成Blog分享出來,於是便新開了這麼一個專題。


第一篇文章取名字的時候讓我非常困惑,我代碼的閱讀是從Launcher開始入手的,也就是Java.exe(如果是windows平台的話)對應的相關代碼,但我又不能取“JVM啟動過程分析”之類的名字,因為從分析主流程的角度來講還深不到這個層次,所以就暫且起了這麼一個奇怪的名字。


這個系列如果能繼續下去的話,不加特殊說明,使用的JDK和JVM版本均為8u20,來自OpenJDK:http://hg.openjdk.java.net/jdk8u


本人是一個JAVA程式員,在分析JVM大量C/C++時難免會有不妥當的地方,還希望各位讀者指正。介於時間有涯而代碼“無涯”,具體的實現細節不可能面面俱到,只著重分析和看懂大致流程和機制,如果有比較重要的細節遺漏之處,歡迎留言討論。


在這個系列中,任何對源檔案位置的描述都使用相對路徑,其中jdk/代表放置Jdk源碼的根目錄,hotspot/代表放置jvm源碼的根目錄。


一、Launcher程式碼分析

(1)Main.c中的main

位置:jdk/src/bin/main.c 

當我們調用java命令時,首先肯定進入的是C/C++的main函數,就像若干年前我寫的那個helloworld一樣。

這個main函數位於jdk/src/bin/main.c,在JDK8中是放置在這個位置,在以前較老版本是放在JVM相關代碼中的。

main.c中幾乎沒有實質的邏輯,主要是複製一些參數,處理在windows平台中的一些調用,之後就把各參數傳遞給JLI_launch進行執行。相關代碼在第125行。

return JLI_Launch(margc, margv,                   sizeof(const_jargs) / sizeof(char *), const_jargs,                   sizeof(const_appclasspath) / sizeof(char *), const_appclasspath,                   FULL_VERSION,                   DOT_VERSION,                   (const_progname != NULL) ? const_progname : *margv,                   (const_launcher != NULL) ? const_launcher : *margv,                   (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE,                   const_cpwildcard, const_javaw, const_ergo_class);



(2)java.c中的JLI_Launch

位置:jdk/src/bin/java.c

java.c中根據注釋可以大概看出這個函數的各參數含義:

JLI_Launch(int argc, char ** argv,              /* main argc, argc */        int jargc, const char** jargv,          /* java args */        int appclassc, const char** appclassv,  /* app classpath */        const char* fullversion,                /* full version defined */        const char* dotversion,                 /* dot version defined */        const char* pname,                      /* program name */        const char* lname,                      /* launcher name */        jboolean javaargs,                      /* JAVA_ARGS */        jboolean cpwildcard,                    /* classpath wildcard*/        jboolean javaw,                         /* windows-only javaw */        jint ergo                               /* ergonomics class policy */

在第236行調用系統函數擷取環境變數,給jrepath,jvmpath和jvmcfg賦值。(每個Java基礎教程裡設定的環境變數在這裡起作用)

    CreateExecutionEnvironment(&argc, &argv,                               jrepath, sizeof(jrepath),                               jvmpath, sizeof(jvmpath),                               jvmcfg,  sizeof(jvmcfg));

第248行載入jvm.dll這個檔案,只是負載檔案到記憶體,並沒有執行任何操作,同時給這個ifn結構體賦值(根據dll抽取函數調用地址賦值),ifn結構體包含三個關鍵的函數指標。

if (!LoadJavaVM(jvmpath, &ifn)) {        return(6);    }
Ifn結構如下:

typedef struct {    CreateJavaVM_t CreateJavaVM;    GetDefaultJavaVMInitArgs_t GetDefaultJavaVMInitArgs;    GetCreatedJavaVMs_t GetCreatedJavaVMs;} InvocationFunctions;
根據函數名可以大概猜到,第一個是建立虛擬機器,第二個是擷取初始參數,第三個是建立很多虛擬機器?(vms代表虛擬機器的複數形式?我猜的。。)。

之後又對參數進行了一些額外的處理(包括擷取classpath、列印調試資訊、添加額外的參數等等),在299行調用JVMInit初始化虛擬機器

    return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret);


(3)Java.c中的JVMInit

位置:jdk/src/bin/java.c

代碼很少,首先列印一下資訊,然後調用ConitueInNewThread函數,從函數名也可以看出,會啟用一個新線程建立JVM。

intJVMInit(InvocationFunctions* ifn, jlong threadStackSize,        int argc, char **argv,        int mode, char *what, int ret){    ShowSplashScreen();    return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);}


(4)Java.c中的ContinueInNewThread

位置:jdk/src/bin/java.c

這個函數依然沒做啥東西,就是封裝了一下參數,然後委派給ContinueInNewThread0。而ContinueInNewThread0開啟一個新的線程,執行JavaMain函數。


(5)Java.c中的JavaMain

位置:jdk/src/bin/java.c

首先在第371行初始化JVM,而InitializeJVM函數做的工作就是調用ifn->createJavaVM,具體的JVM啟動過程水太深因此不在這裡進行分析。如果初始化成功,則會給vm對象和env對象賦值,其中env是一個非常重要的對象,進行JNI調用的時候會頻繁用到。

if (!InitializeJVM(&vm, &env, &ifn)) {        JLI_ReportErrorMessage(JVM_ERROR1);        exit(1);    }
之後檢查一下是否傳入了Jar檔案或者一個類名,如果沒有的話就列印一下Usage

之後第439行擷取主類,擷取主類的方式挺有意思的,在後面會進行分析。接著看看是否拋異常,如果拋異常就直接退出了。

    mainClass = LoadMainClass(env, mode, what);    CHECK_EXCEPTION_NULL_LEAVE(mainClass);


隨後針對JavaFX載入一下東西(如果需要的話),然後擷取main這個方法的ID,組合參數,並Invoke,水到渠成。

其中每一步都檢查是否有異常拋出。

 mainID = (*env)->GetStaticMethodID(env, mainClass, "main",                                       "([Ljava/lang/String;)V");    CHECK_EXCEPTION_NULL_LEAVE(mainID);    /* Build platform specific argument array */    mainArgs = CreateApplicationArgs(env, argv, argc);    CHECK_EXCEPTION_NULL_LEAVE(mainArgs);    /* Invoke main method. */    (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);    /*     * The launcher's exit code (in the absence of calls to     * System.exit) will be non-zero if main threw an exception.     */    ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;



(未完待續)







java檔案是怎執行的

首先:使用javac命令把.java檔案編譯成.class檔案(位元組碼檔案)
然後:JVM(java虛擬機器)裝載.class檔案並翻譯成機器碼後運行java程式;
共同學習-----請參考:
我們手工執行java程式是這樣的:
1 在記事本中或者是UE的文字編輯器中,寫好來源程式;
2 使用javac命令把來源程式編譯成.class檔案;
編譯後的.class(類位元組碼)檔案中會包含以下內容:

ConstantPool:符號表;
FieldInfo:類中的成員變數資訊;
MethodInfo:類中的方法描述;
Attribute:可選的附加節點。
FieldInfo節點包含成員變數的名稱,諸如public,private,static等的標誌。ConstantValue屬性用來儲存靜態不變的成員變數的值。Deprecated和Synthetic被用來標記一個成員變數是不被推薦的或由編譯器產生的。

3 有了.class檔案,我們執行 java 解釋命令就可以運行java程式了。

現在我們主要討論一下,當執行 java這個命令後,會發生什麼事情呢?
首先,JVM裝載.class,也就是類裝載器裝載類位元組碼。一個類裝載器本身也是一個java類,所以,類裝載器自身也需要被另外一個類裝載器裝載,這就出現了類似先有蛋,還是先有雞的問題。但JAVA中的類裝載器的這個問題卻很容易解決。JAVA的虛擬機器(JVM)中內嵌了一個稱為Bootstrap類裝載器,它是用特定於作業系統的本地代碼實現的,屬於JAVA虛擬機器的核心,Bootstrap類不用專門的類裝載器去進行裝載。Bootstrap類負責載入JAVA核心包中的類(即rt.jar檔案中的類),這些類的Class.getClassLoader()方法傳回值為null,即表示是Bootstrap類裝載器。JAVA核心包中有另外兩個類裝載器:ExtClassLoader和AppClassLoader,它們都是用JAVA語言編寫的JAVA類,其中ExtClassLoader類裝載負責載入存放在<JAVA_HOME>/jre/lib/ext目錄下的jar包中的類,AppClassLoader負責載入應用程式的啟動執行類,即當使用java命令去啟動執行一個類時,JAVA虛擬機器使用AppClassLoader載入這個類。在編譯和運行JAVA程式時,都會通過ExtClassLoader類裝載器去<JAVA_HOME>/jre/lib/ext目錄下的JAR包中搜尋要載入的類,所以,如果將包含例如Servlet API的jar包或者是javamail.jar包複製到該目錄下,在編譯Servlet或JavaMail程式時,就不必在CLASSPATH環境變數中增加包含Servlet API的jar包或者是javamail.jar包檔案。
以上,就是一個JAVA程式執行的大致過程。
 
java不可以運行

開啟Java控制台--->安全
點開編輯網站列表
把你瀏覽的網站貼進去
確定,OK

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.