<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    零雨其蒙's Blog

    做優(yōu)秀的程序員
    隨筆 - 59, 文章 - 13, 評論 - 58, 引用 - 0
    數(shù)據(jù)加載中……

    JVM源碼分析-Java運行

         最近在看Java并發(fā)編程實踐和Inside JVM兩本書,發(fā)現(xiàn)如果不真正的了解底層運作,那么永遠(yuǎn)是霧里看花。因此從http://openjdk.java.net/groups/hotspot/上下載了源代碼,準(zhǔn)備研究一番。要想完全研究懂我覺得得對計算機體系結(jié)構(gòu),C,C++編程,Linux內(nèi)核都有比較深入的理解。由于并非從事JVM開發(fā)工作,因此不會研究的那么深入。
    
    入手就從“java 類名”這個Hello World的命令開始吧,簡要的看一下JVM是如何運行起來執(zhí)行main函數(shù)的。

    這個實現(xiàn)使用的是C代碼(位于share/tools/launcher中的java.c),關(guān)注一下是如何執(zhí)行這個命令的。
    過程主要就是按照參數(shù)加載虛擬機,然后找到指定類,執(zhí)行其main方法。
    整個C程序是從main函數(shù)開始:
    1 int
    2 main(int argc, char ** argv)
    3 {
    4     char *jarfile = 0;
    5     char *classname = 0;
    6     char *s = 0;
    7     char *main_class = NULL;
    8     int ret;
    設(shè)置運行時環(huán)境:
       CreateExecutionEnvironment(&argc, &argv,
                                   jrepath, sizeof(jrepath),
                                   jvmpath, sizeof(jvmpath),
                                   original_argv);
    加載JVM:
    1   if (!LoadJavaVM(jvmpath, &ifn)) {
    2       exit(6);
    3     }
    設(shè)置Classpath:
      SetClassPath
    設(shè)置各種參數(shù)
    1   /* set the -Dsun.java.command pseudo property */
    2     SetJavaCommandLineProp(classname, jarfile, argc, argv);
    3 
    4     /* Set the -Dsun.java.launcher pseudo property */
    5     SetJavaLauncherProp();
    6 
    7     /* set the -Dsun.java.launcher.* platform properties */
    8     SetJavaLauncherPlatformProps();

    設(shè)置線程棧大?。?br />
    1   if (threadStackSize == 0) {
    2       struct JDK1_1InitArgs args1_1;
    3       memset((void*)&args1_1, 0, sizeof(args1_1));
    4       args1_1.version = JNI_VERSION_1_1;
    5       ifn.GetDefaultJavaVMInitArgs(&args1_1);  /* ignore return value */
    6       if (args1_1.javaStackSize > 0) {
    7          threadStackSize = args1_1.javaStackSize;
    8       }
    9     }


    創(chuàng)建一個新的線程創(chuàng)建JVM并調(diào)用main方法。
     1  { /* Create a new thread to create JVM and invoke main method */
     2       struct JavaMainArgs args;
     3 
     4       args.argc = argc;
     5       args.argv = argv;
     6       args.jarfile = jarfile;
     7       args.classname = classname;
     8       args.ifn = ifn;
     9 
    10       return ContinueInNewThread(JavaMain, threadStackSize, (void*)&args);
    11     }
    最后在這個線程里調(diào)用了JavaMain,接下來是JavaMain的代碼:
    1 int JNICALL
    2 JavaMain(void * _args)
    3 {
    4     struct JavaMainArgs *args = (struct JavaMainArgs *)_args;
    5     int argc = args->argc;
    6     char **argv = args->argv;
    7     char *jarfile = args->jarfile;
    8     char *classname = args->classname;
    下面就是調(diào)用Java里的main方法了,當(dāng)然首先是加載類:
    1 if (jarfile != 0) {
    2         mainClassName = GetMainClassName(env, jarfile);
    根據(jù)class的名字加載class:
    1  classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);
    2         if (classname == NULL) {
    3             ReportExceptionDescription(env);
    4             goto leave;
    5         }
    6         mainClass = LoadClass(env, classname);
    還有其他情況:
     1   mainClassName = NewPlatformString(env, classname);
     2       if (mainClassName == NULL) {
     3         const char * format = "Failed to load Main Class: %s";
     4         message = (char *)JLI_MemAlloc((strlen(format) + strlen(classname)) *
     5                                    sizeof(char) );
     6         sprintf(message, format, classname);
     7         messageDest = JNI_TRUE;
     8         goto leave;
     9       }
    10       classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);
    11       if (classname == NULL) {
    12         ReportExceptionDescription(env);
    13         goto leave;
    14       }
    15       mainClass = LoadClass(env, classname);
    接下來就是調(diào)用java中的main方法了,這是一個靜態(tài)方法:
    1   /* Get the application's main method */
    2     mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
    3                                        "([Ljava/lang/String;)V");

    確認(rèn)main方法是public的
     1  {    /* Make sure the main method is public */
     2         jint mods;
     3         jmethodID mid;
     4         jobject obj = (*env)->ToReflectedMethod(env, mainClass,
     5                                                 mainID, JNI_TRUE);
     6 
     7         if( obj == NULL) { /* exception occurred */
     8             ReportExceptionDescription(env);
     9             goto leave;
    10         }
    11 
    12         mid =
    13           (*env)->GetMethodID(env,
    14                               (*env)->GetObjectClass(env, obj),
    15                               "getModifiers", "()I");

    1  mods = (*env)->CallIntMethod(env, obj, mid);
    2         if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods))  */
    3             message = "Main method not public.";
    4             messageDest = JNI_TRUE;
    5             goto leave;
    6         }

    構(gòu)建參數(shù):
    1    /* Build argument array */
    2     mainArgs = NewPlatformStringArray(env, argv, argc);
    3     if (mainArgs == NULL) {
    4         ReportExceptionDescription(env);
    5         goto leave;
    6     }
    調(diào)用main方法:
    1  /* Invoke main method. */
    2     (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
    脫離線程:
     1   /*
     2      * Detach the main thread so that it appears to have ended when
     3      * the application's main method exits.  This will invoke the
     4      * uncaught exception handler machinery if main threw an
     5      * exception.  An uncaught exception handler cannot change the
     6      * launcher's return code except by calling System.exit.
     7      */
     8     if ((*vm)->DetachCurrentThread(vm) != 0) {
     9         message = "Could not detach main thread.";
    10         messageDest = JNI_TRUE;
    11         ret = 1;
    12         goto leave;
    13     }

    銷毀虛擬機,得等所有線程都結(jié)束,因為虛擬機是一個守護(hù)線程:
     1 leave:
     2     /*
     3      * Wait for all non-daemon threads to end, then destroy the VM.
     4      * This will actually create a trivial new Java waiter thread
     5      * named "DestroyJavaVM", but this will be seen as a different
     6      * thread from the one that executed main, even though they are
     7      * the same C thread.  This allows mainThread.join() and
     8      * mainThread.isAlive() to work as expected.
     9      */
    10     (*vm)->DestroyJavaVM(vm);

    回過頭來比較重要的幾個方法:
    1 LoadClass
    2 GetStaticMethodID
    3 GetMethodID
    4 CallIntMethod
    5 CallStaticVoidMethod
    6 ContinueInNewThread
    7 LoadJavaVM
    這些方法基本上就是我們平常寫代碼比較關(guān)注的了。

    LoadClass

     1 /*
     2  * Loads a class, convert the '.' to '/'.
     3  */
     4 static jclass
     5 LoadClass(JNIEnv *env, char *name)
     6 {
     7     char *buf = JLI_MemAlloc(strlen(name) + 1);
     8     char *s = buf, *t = name, c;
     9     jclass cls;
    10     jlong start, end;
    11 
    12     if (_launcher_debug)
    13         start = CounterGet();
    14 
    15     do {
    16         c = *t++;
    17         *s++ = (c == '.') ? '/' : c;
    18     } while (c != '\0');
    19     cls = (*env)->FindClass(env, buf);
    20     JLI_MemFree(buf);
    21 
    22     if (_launcher_debug) {
    23         end   = CounterGet();
    24         printf("%ld micro seconds to load main class\n",
    25                (long)(jint)Counter2Micros(end-start));
    26         printf("----_JAVA_LAUNCHER_DEBUG----\n");
    27     }
    28 
    29     return cls;
    30 }

    其中有個主要方法是調(diào)用JNIEnv的FindClass方法去找class:
    在下載的源代碼中jni.h位于share/vm/prims,在網(wǎng)上找到如下代碼:
    http://home.pacifier.com/~mmead/jni/cs510ajp/jni.h 
      1 /*
     2  * We use inlined functions for C++ so that programmers can write:
     3  * 
     4  *    env->FindClass("java/lang/String")
     5  *
     6  * in C++ rather than:
     7  *
     8  *    (*env)->FindClass(env, "java/lang/String")
     9  *
    10  * in C.
    11  */
    12 
    13 struct JNIEnv_ {
    14     const struct JNINativeInterface_ *functions;
    15     void *reserved0;
    16     void *reserved1[6];
    17 #ifdef __cplusplus
    18 
    19     jint GetVersion() {
    20         return functions->GetVersion(this);
    21     }
    22     jclass DefineClass(const char *name, jobject loader, const jbyte *buf,
    23                jsize len) {
    24         return functions->DefineClass(this, name, loader, buf, len);
    25     }
    26     jclass FindClass(const char *name) {
    27         return functions->FindClass(this, name);
    28     }

     JNI是依賴于Java Runtime Interface的:
    /* 
     * We used part of Netscape's Java Runtime Interface (JRI) as the starting
     * point of our design and implementation.
     
    */
    具體可以看這里這里
    注意JNINativeInterface_ 這個結(jié)構(gòu)體,實際上之前說的那些方法,最終都是調(diào)用了它:
      jclass (JNICALL *FindClass)  (JNIEnv *env, const char *name);
      jmethodID (JNICALL *GetStaticMethodID)       (JNIEnv *env, jclass clazz, const char *name, const char *sig);

     void (JNICALL *CallStaticVoidMethod)
          (JNIEnv *env, jclass cls, jmethodID methodID, );
    這種寫法在C++里叫inline function,調(diào)用方法就是像上面寫的那樣:
     1 /*
     2  * We use inlined functions for C++ so that programmers can write:
     3  * 
     4  *    env->FindClass("java/lang/String")
     5  *
     6  * in C++ rather than:
     7  *
     8  *    (*env)->FindClass(env, "java/lang/String")
     9  *
    10  * in C.
    11  */
    share/vm/prims中包含了jni的大量實現(xiàn)代碼,對于上面的概述進(jìn)行了細(xì)化,如果想知道怎么加載例如FindClass這樣的方法,以及它們內(nèi)部到底干了什么,就得看這部分了。

     

    LoadJavaVM
    LoadJavaVM和DestroyJavaVM等跟VM有關(guān)的方法,都與share/vm/prims中的jvm.h,jvm.cpp有關(guān)。
    這個方法解釋如下:
     1 /*
     2  * This file contains additional functions exported from the VM.
     3  * These functions are complementary to the standard JNI support.
     4  * There are three parts to this file:
     5  *
     6  * First, this file contains the VM-related functions needed by native
     7  * libraries in the standard Java API. For example, the java.lang.Object
     8  * class needs VM-level functions that wait for and notify monitors.
     9  *
    10  * Second, this file contains the functions and constant definitions
    11  * needed by the byte code verifier and class file format checker.
    12  * These functions allow the verifier and format checker to be written
    13  * in a VM-independent way.
    14  *
    15  * Third, this file contains various I/O and nerwork operations needed
    16  * by the standard Java I/O and network APIs.
    17  */
    18 
    19 /*
    20  * Bump the version number when either of the following happens:
    21  *
    22  * 1. There is a change in JVM_* functions.
    23  *
    24  * 2. There is a change in the contract between VM and Java classes.
    25  *    For example, if the VM relies on a new private field in Thread
    26  *    class.
    27  */

    這里面包括了VM這個層次上的抽象,大到創(chuàng)建Java線程,加載類,解析字節(jié)碼,小到JVM原生支持的Java方法。
    下面是從bootstrap class loader的代碼,Java的根class loader是c++實現(xiàn)的。
     1 // Returns a class loaded by the bootstrap class loader; or null
     2 // if not found.  ClassNotFoundException is not thrown.
     3 //
     4 // Rationale behind JVM_FindClassFromBootLoader
     5 // a> JVM_FindClassFromClassLoader was never exported in the export tables.
     6 // b> because of (a) java.dll has a direct dependecy on the  unexported
     7 //    private symbol "_JVM_FindClassFromClassLoader@20".
     8 // c> the launcher cannot use the private symbol as it dynamically opens
     9 //    the entry point, so if something changes, the launcher will fail
    10 //    unexpectedly at runtime, it is safest for the launcher to dlopen a
    11 //    stable exported interface.
    12 // d> re-exporting JVM_FindClassFromClassLoader as public, will cause its
    13 //    signature to change from _JVM_FindClassFromClassLoader@20 to
    14 //    JVM_FindClassFromClassLoader and will not be backward compatible
    15 //    with older JDKs.
    16 // Thus a public/stable exported entry point is the right solution,
    17 // public here means public in linker semantics, and is exported only
    18 // to the JDK, and is not intended to be a public API.
    19 
    20 JVM_ENTRY(jclass, JVM_FindClassFromBootLoader(JNIEnv* env,
    21                                               const char* name))
    22   JVMWrapper2("JVM_FindClassFromBootLoader %s", name);

    為了對這個重要的文件有個整體認(rèn)識,下面再摘錄幾段:
    /*************************************************************************
     PART 1: Functions for Native Libraries
     ***********************************************************************
    */
    /*
     * java.lang.Object
     
    */
    JNIEXPORT jint JNICALL
    JVM_IHashCode(JNIEnv *env, jobject obj);

    JNIEXPORT void JNICALL
    JVM_MonitorWait(JNIEnv *env, jobject obj, jlong ms);

    JNIEXPORT void JNICALL
    JVM_MonitorNotify(JNIEnv *env, jobject obj);

    JNIEXPORT void JNICALL
    JVM_MonitorNotifyAll(JNIEnv *env, jobject obj);

    JNIEXPORT jobject JNICALL
    JVM_Clone(JNIEnv *env, jobject obj);
    可以看到對象上有個監(jiān)視器來執(zhí)行線程的Wait和Notify。
    PartI中跟線程有關(guān)的:
     1 /*
     2  * java.lang.Thread
     3  */
     4 JNIEXPORT void JNICALL
     5 JVM_StartThread(JNIEnv *env, jobject thread);
     6 
     7 JNIEXPORT void JNICALL
     8 JVM_StopThread(JNIEnv *env, jobject thread, jobject exception);
     9 
    10 JNIEXPORT jboolean JNICALL
    11 JVM_IsThreadAlive(JNIEnv *env, jobject thread);
    12 
    13 JNIEXPORT void JNICALL
    14 JVM_SuspendThread(JNIEnv *env, jobject thread);
    15 
    16 JNIEXPORT void JNICALL
    17 JVM_ResumeThread(JNIEnv *env, jobject thread);
    18 
    19 JNIEXPORT void JNICALL
    20 JVM_SetThreadPriority(JNIEnv *env, jobject thread, jint prio);
    21 
    22 JNIEXPORT void JNICALL
    23 JVM_Yield(JNIEnv *env, jclass threadClass);
    24 
    25 JNIEXPORT void JNICALL
    26 JVM_Sleep(JNIEnv *env, jclass threadClass, jlong millis);
    27 
    28 JNIEXPORT jobject JNICALL
    29 JVM_CurrentThread(JNIEnv *env, jclass threadClass);
    30 
    31 JNIEXPORT jint JNICALL
    32 JVM_CountStackFrames(JNIEnv *env, jobject thread);
    33 
    34 JNIEXPORT void JNICALL
    35 JVM_Interrupt(JNIEnv *env, jobject thread);
    36 
    37 JNIEXPORT jboolean JNICALL
    38 JVM_IsInterrupted(JNIEnv *env, jobject thread, jboolean clearInterrupted);
    39 
    40 JNIEXPORT jboolean JNICALL
    41 JVM_HoldsLock(JNIEnv *env, jclass threadClass, jobject obj);
    42 
    43 JNIEXPORT void JNICALL
    44 JVM_DumpAllStacks(JNIEnv *env, jclass unused);
    45 
    46 JNIEXPORT jobjectArray JNICALL
    47 JVM_GetAllThreads(JNIEnv *env, jclass dummy);
    第二部分主要是驗證class格式
     1 /*************************************************************************
     2  PART 2: Support for the Verifier and Class File Format Checker
     3  ************************************************************************/
     4 /*
     5  * Return the class name in UTF format. The result is valid
     6  * until JVM_ReleaseUTf is called.
     7  *
     8  * The caller must treat the string as a constant and not modify it
     9  * in any way.
    10  */
    11 JNIEXPORT const char * JNICALL
    12 JVM_GetClassNameUTF(JNIEnv *env, jclass cb);
    13 
    14 /*
    15  * Returns the constant pool types in the buffer provided by "types."
    16  */
    17 JNIEXPORT void JNICALL
    18 JVM_GetClassCPTypes(JNIEnv *env, jclass cb, unsigned char *types);
    19 
    20 /*
    21  * Returns the number of Constant Pool entries.
    22  */
    23 JNIEXPORT jint JNICALL
    24 JVM_GetClassCPEntriesCount(JNIEnv *env, jclass cb);
    25 
    26 /*
    27  * Returns the number of *declared* fields or methods.
    28  */
    29 JNIEXPORT jint JNICALL
    30 JVM_GetClassFieldsCount(JNIEnv *env, jclass cb);

    第三部分主要是對IO和網(wǎng)絡(luò)的支持,包括了File和Socket
     1 /*************************************************************************
     2  PART 3: I/O and Network Support
     3  ************************************************************************/
     4 
     5 /* Note that the JVM IO functions are expected to return JVM_IO_ERR
     6  * when there is any kind of error. The caller can then use the
     7  * platform specific support (e.g., errno) to get the detailed
     8  * error info.  The JVM_GetLastErrorString procedure may also be used
     9  * to obtain a descriptive error string.
    10  */
    11 #define JVM_IO_ERR  (-1)
    12 
    13 /* For interruptible IO. Returning JVM_IO_INTR indicates that an IO
    14  * operation has been disrupted by Thread.interrupt. There are a
    15  * number of technical difficulties related to interruptible IO that
    16  * need to be solved. For example, most existing programs do not handle
    17  * InterruptedIOExceptions specially, they simply treat those as any
    18  * IOExceptions, which typically indicate fatal errors.
    19  *
    20  * There are also two modes of operation for interruptible IO. In the
    21  * resumption mode, an interrupted IO operation is guaranteed not to
    22  * have any side-effects, and can be restarted. In the termination mode,
    23  * an interrupted IO operation corrupts the underlying IO stream, so
    24  * that the only reasonable operation on an interrupted stream is to
    25  * close that stream. The resumption mode seems to be impossible to
    26  * implement on Win32 and Solaris. Implementing the termination mode is
    27  * easier, but it's not clear that's the right semantics.
    28  *
    29  * Interruptible IO is not supported on Win32.It can be enabled/disabled
    30  * using a compile-time flag on Solaris. Third-party JVM ports do not
    31  * need to implement interruptible IO.
    32  */
    33 #define JVM_IO_INTR (-2)

    有個結(jié)論是:整個Hotspot JVM是以JRI為起點進(jìn)行設(shè)計的基于JNI的框架,可以算是一個插件架構(gòu),通過JNI的機制擴展JVM自身。
    另外在share/vm/prims中還能看到大量的jvmti開頭的文件,那么jvmti是什么東東呢?那么看這里
      The JVMTM Tool Interface (JVM TI) is a new native programming interface for use by tools. It provides both a way to inspect the state and to control the execution of applications running in the Java virtual machine (JVM). JVM TI supports the full breadth of tools that need access to JVM state, including but not limited to: profiling, debugging, monitoring, thread analysis, and coverage analysis tools.

    Note: JVM TI replaces the Java Virtual Machine Profiler Interface (JVMPI) and the Java Virtual Machine Debug Interface (JVMDI). JVMPI and JVMDI will be removed in the next major release of J2SETM.


    先寫到這吧,下面一篇應(yīng)該會從整個的JVM架構(gòu)來講一下,然后再去對照Inside JVM和JVM規(guī)范去理解重點代碼,看其是如何實現(xiàn)的。我關(guān)注的重點是OO,IO,多線程以及GC,JIT這幾個方面的實現(xiàn)。另外一部分重點是更基礎(chǔ)的,JVM真正在執(zhí)行層面上如何運行Java字節(jié)碼的,那些堆,棧,棧幀,PC如何創(chuàng)建,如何執(zhí)行指令。
    給自己做一個規(guī)劃吧,列個提綱:
    1 JVM總體架構(gòu)
    2 JVM內(nèi)存模型以及運行時
    3 多線程
    4 GC
    5 OO
    6 IO
    7 JIT

    posted on 2012-04-26 18:05 零雨其蒙 閱讀(25624) 評論(2)  編輯  收藏 所屬分類: 學(xué)習(xí)筆記

    評論

    # re: JVM源碼分析-Java運行  回復(fù)  更多評論   


    java程序語言學(xué)習(xí)教程 http://zuidaima.com/
    2015-06-18 13:40 | zuidaima

    # re: JVM源碼分析-Java運行  回復(fù)  更多評論   

    好,支持!
    2015-08-30 18:36 | hay
    主站蜘蛛池模板: 免费看AV毛片一区二区三区| 久久一本岛在免费线观看2020| 久久国产成人亚洲精品影院| 日本免费网站观看| 黄网站色在线视频免费观看| 免费A级毛片无码免费视| 最近中文字幕高清免费中文字幕mv| 免费无码又爽又刺激一高潮| 久久久久高潮毛片免费全部播放 | 亚洲AV无码专区日韩| 国产AV无码专区亚洲AV漫画| 亚洲综合一区二区| 亚洲AV电影天堂男人的天堂| 亚洲国产成人久久综合| 涩涩色中文综合亚洲| 免费国产高清毛不卡片基地| 国产精品免费一区二区三区四区 | 成在人线av无码免费高潮喷水| 久久国产色AV免费观看| 韩国欧洲一级毛片免费| 国产专区一va亚洲v天堂| 亚洲福利视频一区二区三区| 婷婷亚洲综合五月天小说在线| 波多野结衣免费一区视频| 噼里啪啦电影在线观看免费高清| 亚洲国产成人a精品不卡在线| 亚洲国产精品自在在线观看| 亚洲精品国产品国语在线| 亚洲av无码不卡久久| 一级特黄特色的免费大片视频| 在线看无码的免费网站| 免费a级毛片无码av| 亚洲色欲久久久久综合网| 亚洲福利一区二区| xxxx日本在线播放免费不卡| 国产一卡二卡四卡免费| 中文字幕无码精品亚洲资源网| 亚洲一区二区三区高清不卡| 两个人日本WWW免费版| 女人与禽交视频免费看| 免费人成视频x8x8入口|