最近阅读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。

int
JVMInit(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 -jar somefile.jar时会发生什么(一个)的更多相关文章

  1. 运行Java -jar somefile.jar时发生了什么(二)

    (6)Java.c中的LoadMainClass 位置jdk/src/share/bin/java.c 该方法负责载入main函数所在的类. 该方法首先载入sun.launcher.LauncherH ...

  2. 基于Java的打包jar、war、ear包的作用与区别详解

      本篇文章,小编为大家介绍,基于Java的打包jar.war.ear包的作用与区别详解.需要的朋友参考下   以最终客户的角度来看,JAR文件就是一种封装,他们不需要知道jar文件中有多少个.cla ...

  3. java开发常用jar包介绍(转载)

    jta.jar 标准JTA API必要 commons-collections.jar 集合类 必要 antlr.jar  ANother Tool for Language Recognition ...

  4. java项目打成jar包时引用了第三方jar,此时我们该如何解决呢

    Web项目做多了,反而对单纯的java项目陌生了,今天我们在开发项目的过程中,碰到一个这样的需求:需要将java项目放到linux系统上跑起来,当然这个javaSE项目是带main方法的.我们知道在I ...

  5. IntelliJ IDEA导出Java 可执行Jar包

    原文:IntelliJ IDEA导出Java 可执行Jar包 保证自己的Java代码是没有问题的,在IDEA里面是可以正常运行的,然后,按下面步骤: 打开File -> Project Stru ...

  6. java应用的jar包多合一

    之前开发的java程序由于依赖比较多的jar包,启动命令为" java -classpath .:lib/*.jar 主类名",这种启动方式需要指定类路径.入口类名称,并存在jar ...

  7. IntelliJ IDEA导出Java 可执行Jar包

    extends:http://blog.sina.com.cn/s/blog_3fe961ae0102uy42.html 保证自己的Java代码是没有问题的,在IDEA里面是可以正常运行的,然后,按下 ...

  8. windows下的java项目打jar分别编写在windows与linux下运行的脚本( 本人亲测可用!)

    前言: 最近公司做了一个工具,要将这个工具打包成一个可运行的程序,编写start.bat和start.sh在windows和linux下都可以运行. 在网上找了很多资料,最后终于找到一个可靠的资料,记 ...

  9. Java常用开源jar包

    转:http://blog.csdn.net/kevingao/article/details/8125683 activation~与javaMail有关的jar包,使用javaMail时应与mai ...

随机推荐

  1. Linux渗透+SSH内网转发

    http://www.jb51.net/hack/58514.html http://blog.chinaunix.net/uid-756931-id-353243.html http://blog. ...

  2. POJ 2536 Gopher II(二分图的最大匹配)

    题目链接:http://poj.org/problem?id=2536 题意:已知有n仅仅老鼠的坐标,m个洞的坐标,老鼠的移动速度为V,S秒以后有一仅仅老鹰要吃老鼠,问有多少个老鼠被吃. 非常明晰,二 ...

  3. 使用CSS3制图

    参考资料:http://blog.csdn.net/fense_520/article/details/37892507 本文非转载.为个人原创,转载请先联系博主,谢谢~ 准备: <!DOCTY ...

  4. DRY

    DRY(Don't Repeat Yourself )原则   凡是写过一些代码的程序猿都能够意识到应该避免重复的代码和逻辑.我们通过提取方法,提取抽象类等等措施来达到这一目的.我们总能时不时的听到类 ...

  5. python学习之print输出不换行

    print的即时打印会导致换行,要使得print的输出不换行,可以在字符串或者变量后面加个逗号(“,”),如下: s = "A bird in the hand..." for c ...

  6. POJ 1276  Cash Machine(多重背包)

    Cash Machine Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 24132 Accepted: 8446 Descrip ...

  7. 9patch(.9)怎么去掉自己画上的黑点/黑线

    在自己制作.9.png图片的时候,制作之后所制作的图片上面会显示出制作的痕迹,也即是图片区域上会显示小黑点和黑线.那么为了真正的利用.9.png图片的使用效果.这些瑕疵当然是不能出现的了.因此,要想办 ...

  8. java 线程 新类库中的构件 countDownLatch 使用

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhbmdydWkxOTg4/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  9. Makefile 管理工具 — Automake and Autoconf

    该project下载路径:http://files.cnblogs.com/iTsihang/hello-2.0.zip automake 參考资料:http://www.linuxforum.net ...

  10. Java Swing 树状组件JTree的使用方法(转)

    树中特定的节点可以由 TreePath(封装节点及其所有祖先的对象)标识,或由其显示行(其中显示区域中的每一行都显示一个节点)标识.展开 节点是一个非叶节点(由返回 false 的 TreeModel ...