JVM启动分析

通过openjdk的源码来分析jvm的启动过程,针对linux系统。

jvm的启动入口main():

// openjdk7u/jdk/src/share/bin/main.c

/**
 * main方法
 *
 * argc 参数个数
 * argv 参数数组
 */
int main(int argc, char **argv) {
    return JLI_Launch(...);
}

JLI_Launch()方法:

// openjdk7u/jdk/src/share/bin/java.c

int JLI_Launch(...) {
    // 启动初始化
    InitLauncher(javaw);

    // 选择jre版本
    SelectVersion(argc, argv, &main_class);

    // 创建执行环境
    CreateExecutionEnvironment(...);

    // 加载Java虚拟机
    if (!LoadJavaVM(jvmpath, &ifn)) {
        return (6);
    }

    if (IsJavaArgs()) {
        TranslateApplicationArgs(jargc, jargv, &argc, &argv);
        if (!AddApplicationOptions(appclassc, appclassv)) {
            return (1);
        }
    } else {
        // 读取环境变量CLASSPATH
        cpath = getenv("CLASSPATH");
        if (cpath == NULL) {
            cpath = ".";
        }
        // 设置类路径
        SetClassPath(cpath);
    }

    // 解析命令行参数
    if (!ParseArguments(&argc, &argv, &mode, &what, &ret, jrepath)) {
        return (ret);
    }

    if (mode == LM_JAR) {
        // jar启动模式, 重新设置类路径
        SetClassPath(what);
    }

    SetJavaCommandLineProp(what, argc, argv);

    SetJavaLauncherProp();

    SetJavaLauncherPlatformProps();

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

InitLauncher()方法:

// openjdk7u/jdk/src/solaris/bin/java_md_common.c

void InitLauncher(jboolean javaw) {
    // 读取环境变量_JAVA_LAUNCHER_DEBUG, 来设置是否打印debug信息
    JLI_SetTraceLauncher();
}

JLI_SetTraceLauncher()方法:

// openjdk7u/jdk/src/share/bin/jli_util.c

// 是否开启debug模式
static jboolean _launcher_debug = JNI_FALSE;

void JLI_SetTraceLauncher() {
    if (getenv(JLDEBUG_ENV_ENTRY) != 0) {
        _launcher_debug = JNI_TRUE;
        JLI_TraceLauncher("----%s----\n", JLDEBUG_ENV_ENTRY);
    }
}

jboolean JLI_IsTraceLauncher() {
    return _launcher_debug;
}

void JLI_TraceLauncher(const char *fmt, ...) {
    if (_launcher_debug != JNI_TRUE) return;
    vprintf(fmt, vl);
}

后续会调用JLI_IsTraceLauncher()JLI_TraceLauncher()方法输出debug信息。

LoadJavaVM()方法:

// openjdk7u/jdk/src/solaris/bin/java_md_solinux.c

jboolean LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) {
    // 装载动态链接库, jre/lib/libjvm.so
    libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
    // 导出动态链接库函数JNI_CreateJavaVM, 挂载到ifn
    ifn->CreateJavaVM = (CreateJavaVM_t) dlsym(libjvm, "JNI_CreateJavaVM");
    // 导出动态链接库函数JNI_GetDefaultJavaVMInitArgs, 挂载到ifn
    ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t) dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs");
    // 导出动态链接库函数JNI_GetCreatedJavaVMs, 挂载到ifn
    ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t) dlsym(libjvm, "JNI_GetCreatedJavaVMs");
    return JNI_TRUE;
}

JVMInit()方法:

// openjdk7u/jdk/src/solaris/bin/java_md_solinux.c

int JVMInit(...) {
    ShowSplashScreen();
    return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);
}

ContinueInNewThread()方法:

// openjdk7u/jdk/src/share/bin/java.c

int ContinueInNewThread(InvocationFunctions *ifn, jlong threadStackSize, ...) {
    {
        //创建一个新的线程来执行JavaMain方法
        rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void *) &args);
    }
}

JavaMain()方法:

// openjdk7u/jdk/src/share/bin/java.c

int JNICALL JavaMain(void *_args) {
    // 初始化虚拟机
    if (!InitializeJVM(&vm, &env, &ifn)) {
        exit(1);
    }

    // 加载主类
    mainClass = LoadMainClass(env, mode, what);

    // 获取主类的main()方法id
    mainID = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V");

    // 创建main方法参数
    mainArgs = CreateApplicationArgs(env, argv, argc);

    // 调用main方法
    (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);

    // main方法退出
    ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;

    // 销毁虚拟机
    LEAVE();
}

static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn) {
    r = ifn->CreateJavaVM(pvm, (void **) penv, &args);
    return r == JNI_OK;
}

static jclass LoadMainClass(JNIEnv *env, int mode, char *name) {
    // 获取sun.launcher.LauncherHelper类
    jclass cls = GetLauncherHelperClass(env);

    // 获取LauncherHelper类的checkAndLoadMain()方法id
    mid = (*env)->GetStaticMethodID(env, cls, "checkAndLoadMain", "(ZILjava/lang/String;)Ljava/lang/Class;");

    // 调用LauncherHelper类的checkAndLoadMain()方法检查并加载主类
    result = (*env)->CallStaticObjectMethod(env, cls, mid, USE_STDERR, mode, str);

    return (jclass) result;
}

jclass GetLauncherHelperClass(JNIEnv *env) {
    return FindBootStrapClass(env, "sun/launcher/LauncherHelper");
}

InitializeJVM()方法调用前面挂载的CreateJavaVM()方法,也就是JNI_CreateJavaVM()方法。

sun.launcher.LauncherHelpercheckAndLoadMain()方法检查并加载主类过程:

public enum LauncherHelper {

    private static final int LM_UNKNOWN = 0;
    private static final int LM_CLASS = 1;
    private static final int LM_JAR = 2;

    /**
     * 检查并加载主类
     *
     * @param useStdErr 是否使用标准错误输出
     * @param mode      模式, 对应LM_UNKNOWN、LM_CLASS、LM_JAR
     * @param name      主类名
     * @return          主类Class
     */
    public static Class<?> checkAndLoadMain(boolean useStdErr, int mode, String name) {
        PrintStream printStream = useStdErr ? System.err : System.out;
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        String className = null;
        switch (mode) {
            // class启动模式
            case 1:
                className = name;
                break;
            // jar启动模式
            case 2:
                // 通过jar包中MANIFEST.MF文件的Main-Class获取主类名
                className = getMainClassFromJar(printStream, name);
                break;
            default:
                throw new InternalError(mode + ": Unknown launch mode");
        }

        className = className.replace('/', '.');

        Class mainClass = null;
        try {
            // 加载主类
            mainClass = classLoader.loadClass(className);
        } catch (ClassNotFoundException var8) {
            // 主类加载失败, 退出
            abort(printStream, var8, "java.launcher.cls.error1", new Object[]{className});
        }

        // 检查主类的main()方法, public static void main([Ljava.lang.String)
        getMainMethod(printStream, mainClass);
        return mainClass;
    }

}

jvm的启动模式:

  • jar启动模式: java -jar main.jar
  • class启动模式: java org.txazo.test.Main

jvm的整体启动流程:

  • 准备工作,包括查找jre、jvm
  • 装载动态链接库
  • 解析jvm参数
  • 启动虚拟机
  • 加载主类,并调用主类的main()方法
http://www.txazo.com/jvm/jvm-startup.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值