OpenJDK源码分析(2)_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > OpenJDK源码分析(2)

OpenJDK源码分析(2)

 2012/1/31 9:22:36  ningandjin  程序员俱乐部  我要评论(0)
  • 摘要:找到jvm.dll之后呢?——加载。也就是获取到应该加载的jvmPath之后,java.c接下来执行到263行:if(!LoadJavaVM(jvmpath,&ifn)){exit(6);},通过java_md.c的LoadJavaVM函数来加载整个JVM虚拟机,该方法有2个参数:第一个是我们之前获取得到的jvm.dll的绝对路径;另一个是main函数一开始就初始化的一个结构体InvocationFunctions。LoadJVM首先通过LoadLibrary函数加载了jvm.dll
  • 标签:源码 jdk 分析
  
找到jvm.dll之后呢?
——加载。

    也就是获取到应该加载的jvmPath之后,java.c接下来执行到263行:
 
  if (!LoadJavaVM(jvmpath, &ifn)) {
      exit(6);
    }
,通过java_md.c的LoadJavaVM函数来加载整个JVM虚拟机,该方法有2个参数: 第一个是我们之前获取得到的jvm.dll的绝对路径;
     另一个是main函数一开始就初始化的一个结构体InvocationFunctions。

   LoadJVM首先通过LoadLibrary函数加载了jvm.dll,然后把其中的2个方法JNI_CreateJavaVM 和 JNI_GetDefaultJavaVMInitArgs 挂载到参数ifn的结构体中。
/* Load the Java VM DLL */
    if ((handle = LoadLibrary(jvmpath)) == 0) {
        ReportErrorMessage2("Error loading: %s", (char *)jvmpath, JNI_TRUE);
        return JNI_FALSE;
    }

    /* Now get the function addresses */
    ifn->CreateJavaVM =
        (void *)GetProcAddress(handle, "JNI_CreateJavaVM");
    ifn->GetDefaultJavaVMInitArgs =
        (void *)GetProcAddress(handle, "JNI_GetDefaultJavaVMInitArgs");

   
    加载完jvm.dll,接下来main函数继续初始化接收到的所有参数,然后把所有初始化好的jvm参数和之前我们加载好的InvocationFunctions一起赋值给JavaMainArgs
struct JavaMainArgs {
  int     argc;
  char ** argv;
  char *  jarfile;
  char *  classname;
  InvocationFunctions ifn;
};

    构造好JavaMainArgs 之后,会执行到java.c的370行。
ContinueInNewThread(JavaMain, threadStackSize, (void*)&args, ret);
新起一个线程去执行JavaMain函数。
    JavaMain函数经过一系列初始化之后,会调用java.c中的InitializeJVM函数来初始化一个JVM虚拟机,该函数主要执行逻辑就一句话,在java.c的1269行
  r = ifn->CreateJavaVM(pvm, (void **)penv, &args);

    就是通过调用我们之前挂在的InvocationFunctions的CreateJVM创建一个虚拟机,而CreateJVM挂载的是jvm.dll中的JNI_CreateJavaVM方法。JNI_CreateJavaVM方法的源代码在\hotspot\src\share\vm\prims\jni.cpp中。该方法的定义如下:
_JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args)
该方法有3个参数,都是从java.c的InitializeJVM函数传过来的:   第一个参数是javaVM指针的指针;
       第二个参数是JNIEnv类型的指针的指针;
       第三个参数是一个虚拟机的参数的指针。该函数主要的功能
result = Threads::create_vm((JavaVMInitArgs*) args, &can_try_again);
  if (result == JNI_OK) {
    JavaThread *thread = JavaThrad::current();
    /* thread is thread_in_vm heere */
    *vm = (JavaVM *)(&main_vm);
    *(JNIEnv**)penv = thread->jni_environment();

    一是根据jvm启动参数构建一个VM虚拟机;
    二是构建了一个JNIEnv的实例挂载到main中的JNIEnv结构的指针。这样,java.c的InitializeJVM函数就可以使用这个JNIEnv实例继续做下面的操作。
    构造好了VM实例和JNIEnv,JavaMain函数开始加载Class,它首先会寻找java程序的入口类,即MainClass。
if (jarfile != 0) {
        mainClassName = GetMainClassName(env, jarfile);
        .....
    } else {
        mainClassName = NewPlatformString(env, classname);
      ....
    }
如果执行的是jar文件,则会通过GetMainClassName函数查找jar中的MainClass.具体逻辑就是先实例化java/util/jar/JarFile类,然后获取执行的jar文件中的Manifest对象的"Main-Class"属性。——即jar包中的META-INF/MANIFEST.MF文件的"Main-Class"属性。
       如果直接是执行的java类,就直接以该类为MainClass。然后调用GetStaticMethodID函数获MainClass中的public static void main(str[] args)方法,找到MainClass中的入口函数,就会初始化MainClass的参数
 mainArgs = NewPlatformStringArray(env, argv, argc);
,然后调用前面获取到的JNIEnv实例调用CallStaticVoidMethod方法执行入口函数。
/* Invoke main method. */
    (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);

这样,程序才执行到我们自己所写的代码。

    
发表评论
用户名: 匿名