文档章节

用Java这么久,你能说出Java启动过程嘛?别吹了,来看看

吴小编
 吴小编
发布于 2014/09/05 15:13
字数 1801
阅读 38
收藏 1

首先要去openJDK上下个源码。我这里下到的是openjdk-7-fcs-src-b147-27_jun_2011。

[java] view plaincopyprint?

  1. </pre>Java.exe这个程序的启动main函数在<br style="padding:0px; margin:0px; outline:none; list-style:none; border:0px none" /><strong>Java.c (hotspot\src\share\tools\launcher)</strong><br style="padding:0px; margin:0px; outline:none; list-style:none; border:0px none" />main函数的实现如下:<p></p><p style="padding-top:1em; padding-bottom:1em; margin-top:0px; margin-bottom:0px; outline:none; list-style:none; border:0px none; color:rgb(51,51,51); font-family:'Droid Sans',Arial,Verdana,sans-serif; font-size:16px; line-height:24px; orphans:2; widows:2"></p><pre name="code" class="java"char *jarfile = 0;  

  2.     char *classname = 0;  

  3.     char *s = 0;  

  4.     char *main_class = NULL;  

  5.     int ret;  

  6.     InvocationFunctions ifn;  

  7.     jlong start, end;  

  8.     char jrepath[MAXPATHLEN], jvmpath[MAXPATHLEN];  

  9.     char ** original_argv = argv;  

  10.   

  11.     if (getenv("_JAVA_LAUNCHER_DEBUG") != 0) {  

  12.         _launcher_debug = JNI_TRUE;  

  13.         printf("----_JAVA_LAUNCHER_DEBUG----\n");  

  14.     }  

  15.   

  16. #ifndef GAMMA  

  17.     /* 

  18.      * 确定一下版本 是1.4 ,1.5 ,1.6 

  19.      * Make sure the specified version of the JRE is running. 

  20.      * 

  21.      * There are three things to note about the SelectVersion() routine: 

  22.      *  1) If the version running isn't correct, this routine doesn't 

  23.      *     return (either the correct version has been exec'd or an error 

  24.      *     was issued). 

  25.      *  2) Argc and Argv in this scope are *not* altered by this routine. 

  26.      *     It is the responsibility of subsequent code to ignore the 

  27.      *     arguments handled by this routine. 

  28.      *  3) As a side-effect, the variable "main_class" is guaranteed to 

  29.      *     be set (if it should ever be set).  This isn't exactly the 

  30.      *     poster child for structured programming, but it is a small 

  31.      *     price to pay for not processing a jar file operand twice. 

  32.      *     (Note: This side effect has been disabled.  See comment on 

  33.      *     bugid 5030265 below.) 

  34.      */  

  35.     SelectVersion(argc, argv, &main_class);  

  36. #endif /* ifndef GAMMA */  

  37.   

  38.     /* 把参数都拿出来 */  

  39.     {  

  40.       int i;  

  41.       original_argv = (char**)JLI_MemAlloc(sizeof(char*)*(argc+1));  

  42.       for(i = 0; i < argc+1; i++)  

  43.         original_argv[i] = argv[i];  

  44.     }  

  45.   

  46.    /** 

  47.     * 建立执行环境,比如看看jre 有没有安装,读一下jre的路径,jvm.cfg 

  48.     */  

  49.     CreateExecutionEnvironment(&argc, &argv,  

  50.                                jrepath, sizeof(jrepath),  

  51.                                jvmpath, sizeof(jvmpath),  

  52.                                original_argv);  

  53.   

  54.     printf("Using java runtime at: %s\n", jrepath);  

  55.   

  56.     ifn.CreateJavaVM = 0;  

  57.     ifn.GetDefaultJavaVMInitArgs = 0;  

  58.   

  59.     //一个计时器之类的  

  60.     if (_launcher_debug)  

  61.       start = CounterGet();  

  62.     //载入JVM了 载入dll啦,这里会调用JNI_CreateJavaVM,把JVM线程跑起来  

  63.     if (!LoadJavaVM(jvmpath, &ifn)) {  

  64.       exit(6);  

  65.     }  

  66.     //计时器,开启JVM线程用了多少时间呢  

  67.     if (_launcher_debug) {  

  68.       end   = CounterGet();  

  69.       printf("%ld micro seconds to LoadJavaVM\n",  

  70.              (long)(jint)Counter2Micros(end-start));  

  71.     }  

  72.   

  73. #ifdef JAVA_ARGS  /* javac, jar and friends. */  

  74.     progname = "java";  

  75. #else             /* java, oldjava, javaw and friends */  

  76. #ifdef PROGNAME  

  77.     progname = PROGNAME;  

  78. #else  

  79.     progname = *argv;  

  80.     if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) {  

  81.         progname = s + 1;  

  82.     }  

  83. #endif /* PROGNAME */  

  84. #endif /* JAVA_ARGS */  

  85.     ++argv;  

  86.     --argc;  

  87.   

  88. #ifdef JAVA_ARGS  

  89.     /* 处理命令行的参数了 */  

  90.     TranslateApplicationArgs(&argc, &argv);  

  91.     if (!AddApplicationOptions()) {  

  92.         exit(1);  

  93.     }  

  94. #endif  

  95.   

  96.     /* 设置默认的classpath */  

  97.     if ((s = getenv("CLASSPATH")) == 0) {  

  98.         s = ".";  

  99.     }  

  100. #ifndef JAVA_ARGS  

  101.     SetClassPath(s);  

  102. #endif  

  103.   

  104.     /* 

  105.      *  解析命令行参数,比如 -jar -cp -help -h -version 

  106.      *  -verbose:gc -Xdebug -Xverify -Xrunhprof 等都在这里处理的 

  107.      */  

  108.     if (!ParseArguments(&argc, &argv, &jarfile, &classname, &ret, jvmpath)) {  

  109.       exit(ret);  

  110.     }  

  111.   

  112.     /* 特别处理一下 -jar的classpath */  

  113.     if (jarfile != 0) {  

  114.         SetClassPath(jarfile);  

  115.     }  

  116.   

  117.     /* set the -Dsun.java.command pseudo property */  

  118.     SetJavaCommandLineProp(classname, jarfile, argc, argv);  

  119.   

  120.     /* Set the -Dsun.java.launcher pseudo property */  

  121.     SetJavaLauncherProp();  

  122.   

  123.     /* set the -Dsun.java.launcher.* platform properties */  

  124.     SetJavaLauncherPlatformProps();  

  125.   

  126. #ifndef GAMMA  

  127.     /* Show the splash screen if needed */  

  128.     ShowSplashScreen();  

  129. #endif  

  130.   

  131.     /* 

  132.      * Done with all command line processing and potential re-execs so 

  133.      * clean up the environment. 

  134.      */  

  135.     (void)UnsetEnv(ENV_ENTRY);  

  136. #ifndef GAMMA  

  137.     (void)UnsetEnv(SPLASH_FILE_ENV_ENTRY);  

  138.     (void)UnsetEnv(SPLASH_JAR_ENV_ENTRY);  

  139.   

  140.     JLI_MemFree(splash_jar_entry);  

  141.     JLI_MemFree(splash_file_entry);  

  142. #endif  

  143.   

  144.     /* 

  145.      * 线程的栈大小设置,没有设置就是默认的0 

  146.      */  

  147.     if (threadStackSize == 0) {  

  148.       struct JDK1_1InitArgs args1_1;  

  149.       memset((void*)&args1_1, 0, sizeof(args1_1));  

  150.       args1_1.version = JNI_VERSION_1_1;  

  151.       ifn.GetDefaultJavaVMInitArgs(&args1_1);  /* ignore return value */  

  152.       if (args1_1.javaStackSize > 0) {  

  153.          threadStackSize = args1_1.javaStackSize;  

  154.       }  

  155.     }  

  156.   

  157.     { /* Java的参数 把这个参数给JavaMain方法,执行JavaMain方法 */  

  158.       struct JavaMainArgs args;  

  159.   

  160.       args.argc = argc;  

  161.       args.argv = argv;  

  162.       args.jarfile = jarfile;  

  163.       args.classname = classname;  

  164.       args.ifn = ifn;  

  165.       //执行JavaMain,就是Java的主函数  

  166.       return ContinueInNewThread(JavaMain, threadStackSize, (void*)&args);  

  167.     }  



ContinueInNewThread方法创建了一个线程来执行JavaMain,因此后面执行的就是JavaMain。

JavaMain是这样的:

   

[java] view plaincopyprint?

  1.   //首先是取得命令行参数 执行的classname jar之类的东西  

  2.   struct JavaMainArgs *args = (struct JavaMainArgs *)_args;  

  3.    int argc = args->argc;  

  4.    char **argv = args->argv;  

  5.    char *jarfile = args->jarfile;  

  6.    char *classname = args->classname;  

  7.    InvocationFunctions ifn = args->ifn;  

  8.   

  9.    JavaVM *vm = 0;  

  10.    JNIEnv *env = 0;  

  11.    jstring mainClassName;  

  12.    jclass mainClass;  

  13.    jmethodID mainID;  

  14.    jobjectArray mainArgs;  

  15.    int ret = 0;  

  16.    jlong start, end;  

  17.   

  18.    /* 

  19.     * Error message to print or display; by default the message will 

  20.     * only be displayed in a window. 

  21.     */  

  22.    char * message = "Fatal exception occurred.  Program will exit.";  

  23.    jboolean messageDest = JNI_FALSE;  

  24.   

  25.    /* Initialize the virtual machine */  

  26.    //计时器又来了  

  27.    if (_launcher_debug)  

  28.        start = CounterGet();  

  29.    //初始化JVM虚拟机 这里主要去调用了 JNI_CreateJavaVM -->Threads::create_vm  

  30.    //这里做了很多事情,Threads::create_vm 以后再分析。这里只要知道把JVM起来了。  

  31.    if (!InitializeJVM(&vm, &env, &ifn)) {  

  32.        ReportErrorMessage("Could not create the Java virtual machine.",  

  33.                           JNI_TRUE);  

  34.        exit(1);  

  35.    }  

  36.   

  37.    if (printVersion || showVersion) {  

  38.        PrintJavaVersion(env);  

  39.        if ((*env)->ExceptionOccurred(env)) {  

  40.            ReportExceptionDescription(env);  

  41.            goto leave;  

  42.        }  

  43.        if (printVersion) {  

  44.            ret = 0;  

  45.            message = NULL;  

  46.            goto leave;  

  47.        }  

  48.        if (showVersion) {  

  49.            fprintf(stderr, "\n");  

  50.        }  

  51.    }  

  52.   

  53.    /* mainclass和jar总要指定一个吧,不然java没法跑 */  

  54.    if (jarfile == 0 && classname == 0) {  

  55.        PrintUsage();  

  56.        message = NULL;  

  57.        goto leave;  

  58.    }  

  59.   

  60. ifndef GAMMA  

  61.    FreeKnownVMs();  /* after last possible PrintUsage() */  

  62. endif  

  63.    //由来一个计时器  

  64.    if (_launcher_debug) {  

  65.        end   = CounterGet();  

  66.        printf("%ld micro seconds to InitializeJVM\n",  

  67.               (long)(jint)Counter2Micros(end-start));  

  68.    }  

  69.   

  70.    /* 拿到了应用的参数 打印一下看看 */  

  71.    if (_launcher_debug) {  

  72.        int i = 0;  

  73.        printf("Main-Class is '%s'\n", classname ? classname : "");  

  74.        printf("Apps' argc is %d\n", argc);  

  75.        for (; i < argc; i++) {  

  76.            printf("    argv[%2d] = '%s'\n", i, argv[i]);  

  77.        }  

  78.    }  

  79.   

  80.    ret = 1;  

  81.   

  82.    /* 

  83.     *  取得MainClass 

  84.     */  

  85.    if (jarfile != 0) {  

  86.        mainClassName = GetMainClassName(env, jarfile);  

  87.        if ((*env)->ExceptionOccurred(env)) {  

  88.            ReportExceptionDescription(env);  

  89.            goto leave;  

  90.        }  

  91.        if (mainClassName == NULL) {  

  92.          const char * format = "Failed to load Main-Class manifest "  

  93.                                "attribute from\n%s";  

  94.          message = (char*)JLI_MemAlloc((strlen(format) + strlen(jarfile)) *  

  95.                                    sizeof(char));  

  96.          sprintf(message, format, jarfile);  

  97.          messageDest = JNI_TRUE;  

  98.          goto leave;  

  99.        }  

  100.        classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);  

  101.        if (classname == NULL) {  

  102.            ReportExceptionDescription(env);  

  103.            goto leave;  

  104.        }  

  105.        //载入类转为mainClass,它是jclass结构体  

  106.        mainClass = LoadClass(env, classname);  

  107.        if(mainClass == NULL) { /* exception occured */  

  108.            const char * format = "Could not find the main class: %s. Program will exit.";  

  109.            ReportExceptionDescription(env);  

  110.            message = (char *)JLI_MemAlloc((strlen(format) +  

  111.                                            strlen(classname)) * sizeof(char) );  

  112.            messageDest = JNI_TRUE;  

  113.            sprintf(message, format, classname);  

  114.            goto leave;  

  115.        }  

  116.        (*env)->ReleaseStringUTFChars(env, mainClassName, classname);  

  117.    } else {  

  118.      //前面处理jar的情况 这里处理没有指定jar的情况  

  119.      mainClassName = NewPlatformString(env, classname);  

  120.      if (mainClassName == NULL) {  

  121.        const char * format = "Failed to load Main Class: %s";  

  122.        message = (char *)JLI_MemAlloc((strlen(format) + strlen(classname)) *  

  123.                                   sizeof(char) );  

  124.        sprintf(message, format, classname);  

  125.        messageDest = JNI_TRUE;  

  126.        goto leave;  

  127.      }  

  128.      classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);  

  129.      if (classname == NULL) {  

  130.        ReportExceptionDescription(env);  

  131.        goto leave;  

  132.      }  

  133.      //上面处理utf8的,我也没看过,应该不是核心 不管了,这里载入MainClass  

  134.      mainClass = LoadClass(env, classname);  

  135.      if(mainClass == NULL) { /* exception occured */  

  136.        const char * format = "Could not find the main class: %s.  Program will exit.";  

  137.        ReportExceptionDescription(env);  

  138.        message = (char *)JLI_MemAlloc((strlen(format) +  

  139.                                        strlen(classname)) * sizeof(char) );  

  140.        messageDest = JNI_TRUE;  

  141.        sprintf(message, format, classname);  

  142.        goto leave;  

  143.      }  

  144.      (*env)->ReleaseStringUTFChars(env, mainClassName, classname);  

  145.    }  

  146.   

  147.    /* 找到MainClass main方法 当然这个main必须是由String[]参数的 */  

  148.    mainID = (*env)->GetStaticMethodID(env, mainClass, "main",  

  149.                                       "([Ljava/lang/String;)V");  

  150.    //找不到就挂了呗  

  151.    if (mainID == NULL) {  

  152.        if ((*env)->ExceptionOccurred(env)) {  

  153.            ReportExceptionDescription(env);  

  154.        } else {  

  155.          message = "No main method found in specified class.";  

  156.          messageDest = JNI_TRUE;  

  157.        }  

  158.        goto leave;  

  159.    }  

  160.   

  161.    {    /* main函数必须是public的 */  

  162.        jint mods;  

  163.        jmethodID mid;  

  164.        //这里拿出来的是 java.lang.reflect.Method  

  165.        jobject obj = (*env)->ToReflectedMethod(env, mainClass,  

  166.                                                mainID, JNI_TRUE);  

  167.   

  168.        if( obj == NULL) { /* exception occurred */  

  169.            ReportExceptionDescription(env);  

  170.            goto leave;  

  171.        }  

  172.        // 一个反射 调用的 java.lang.reflect.Method.getModifiers  

  173.        // 找到修饰符 看看是不是public  

  174.        mid =  

  175.          (*env)->GetMethodID(env,  

  176.                              (*env)->GetObjectClass(env, obj),  

  177.                              "getModifiers""()I");  

  178.        if ((*env)->ExceptionOccurred(env)) {  

  179.            ReportExceptionDescription(env);  

  180.            goto leave;  

  181.        }  

  182.        // public就是1,这个看java的代码里就能找到所有的定义  

  183.        mods = (*env)->CallIntMethod(env, obj, mid);  

  184.        if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */  

  185.            message = "Main method not public.";  

  186.            messageDest = JNI_TRUE;  

  187.            goto leave;  

  188.        }  

  189.    }  

  190.   

  191.    /* 把Java程序的参数都放好 */  

  192.    mainArgs = NewPlatformStringArray(env, argv, argc);  

  193.    if (mainArgs == NULL) {  

  194.        ReportExceptionDescription(env);  

  195.        goto leave;  

  196.    }  

  197.   

  198.    /* 调用Java的Main方法 */  

  199.    (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);  

  200.   

  201.    /* 

  202.     *  

  203.     * 遇到异常返回值就是非0 

  204.     */  

  205.    ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;  

  206.   

  207.    /* 

  208.     * Detach the main thread so that it appears to have ended when 

  209.     * the application's main method exits.  This will invoke the 

  210.     * uncaught exception handler machinery if main threw an 

  211.     * exception.  An uncaught exception handler cannot change the 

  212.     * launcher's return code except by calling System.exit. 

  213.     */  

  214.    if ((*vm)->DetachCurrentThread(vm) != 0) {  

  215.        message = "Could not detach main thread.";  

  216.        messageDest = JNI_TRUE;  

  217.        ret = 1;  

  218.        goto leave;  

  219.    }  

  220.   

  221.    message = NULL;  

  222.   

  223. leave:  

  224.    /* 

  225.     * 这里就是退出了 

  226.     * Wait for all non-daemon threads to end, then destroy the VM. 

  227.     * This will actually create a trivial new Java waiter thread 

  228.     * named "DestroyJavaVM", but this will be seen as a different 

  229.     * thread from the one that executed main, even though they are 

  230.     * the same C thread.  This allows mainThread.join() and 

  231.     * mainThread.isAlive() to work as expected. 

  232.     */  

  233.    (*vm)->DestroyJavaVM(vm);  

  234.   

  235.    if(message != NULL && !noExitErrorMessage)  

  236.      ReportErrorMessage(message, messageDest);  

  237.    return ret;  



如果您会Java,但是还不会JVM,还看不懂JVM,那么来学习下葛老师开设的深入浅出JVM课程吧。http://www.dataguru.cn/myclassnew.php?mod=new_basicforlesson&op=basic&lessonid=208

或者加入QQ 群397196583,一起来讨论JVM看不通看不懂的地方。



© 著作权归作者所有

吴小编
粉丝 19
博文 69
码字总数 47867
作品 0
海淀
私信 提问
Android开发学习总结(二)——使用Android Studio搭建Android集成开发环境

一、Android Studio简单介绍   2013年GoogleI/O大会首次发布了Android Studio IDE(Android平台集成开发环境)。它基于Intellij IDEA开发环境,旨在取代Eclipse和ADT(Android开发者工具)...

哒哒成晨
05/14
0
0
每天10道Java面试题,跟我走,offer有!

1.简述JDK、JRE、JVM? 2.JDK、JRE、JVM三者的有什么联系和区别? 3、简述Java程序编译和运行的过程? 4、请说出八种基础数据类型及字节大小? 顺便在此给大家推荐一个Java架构方面的交流学习...

Java干货分享
2018/11/04
0
0
图文详解Android Studio搭建Android集成开发环境的过程

有很长一段时间没有更新博客了,最近实在是太忙了,没有时间去总结,现在终于可以有时间去总结一些Android上面的东西了,很久以前写过这篇关于使用Android Studio搭建Android集成开发环境,不...

查杰
2018/06/29
0
0
Java程序的加密和反加密

写在前面的话:写这篇文档的目的是让大家能更深入的了解 Java技术,而不是教你怎么去破解Java程序;武器没有罪过,要看是好人用它还是坏人用它。 首先我们来看看Java程序的反加密,也就是通常...

andogo
2014/05/15
265
0
Android 使用自带的HttpClient进行https请求出现403的解决过程记录

出现的过程 最近在用程序模拟一个web站的https登录,然后进行一些后续操作的小玩意。先使用java程序写测试代码,测试通过移植到android。 java基于httpclient-4.3.1.jar开发。 android端使用...

atearsan
2014/03/05
0
1

没有更多内容

加载失败,请刷新页面

加载更多

思维导图XMind 8 Pro 绿化方法(附序列号)

按部就班: Step 1 -全新下载最新版本的 Xmind 8(注必须是英文官方的版本,中文代{过}{滤}理网站的版本修改过,无法使用pj); Step 2 -安装完毕后,点击文末的下载按钮下载pj补丁文件包,将...

一只小青蛙
58分钟前
6
0
数据结构(ER数据库)设计规范

表命名规范 表命名的规则分为3个层级,层级之间通过_分割,例如b_r_identity、d_l_identity。规约为: [leavel]_[type]_[name] [leavel] 表示数据库表的层级和功能,分为: s:业务无关的系统...

随风溜达的向日葵
今天
5
0
阿里Sentinel控制台源码修改-对接Apollo规则持久化

https://github.com/alibaba/Sentinel/wiki/%E5%9C%A8%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Sentinel 动态规则扩展 https://github.com/alibaba/Sentinel/wiki......

jxlgzwh
昨天
4
0
在Linux系统中创建SSH服务器别名

如果你经常通过 SSH 访问许多不同的远程系统,这个技巧将为你节省一些时间。你可以通过 SSH 为频繁访问的系统创建 SSH 别名,这样你就不必记住所有不同的用户名、主机名、SSH 端口号和 IP 地...

老孟的Linux私房菜
昨天
10
0
高德API入门教程

项目需求 1、实现打开地图就能定位到中心显示标注点 2、点击标注显示保利可爱岛的详细信息 3、实现导航功能 <!doctype html><html><head> <meta charset="utf-8"> <meta http-......

我叫小糖主
昨天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部