JVM启动分析

JVM 源码分析之 JVM 启动流程 执行 Java 类的 main 方法,程序就能运行起来,main 方法的背后,虚拟机究竟发生了什么?参数进行特殊处理,并设置 threadStackSize,因为参数格式比较特殊,其它是 key/value 键值对,它是。装载完 JVM 环境之后,需要对启动参数进行解析,其实在装载 JVM 环境的过程中已经解析了部分参数,该过程通过。Java 代码执行时需要一个 JVM 环境,JVM 环境的创建包括两部分:JVM.dll 文件的查找和装载。中,根据当前系统类型,加载对应的配置文件,所以在不同的系统中, 阅读详情

通过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.LauncherHelper的checkAndLoadMain()方法检查并加载主类过程:

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
Jvm(jdk8)源码分析1-java命令启动流程详解 1.概述 现在大多数互联网公司都是使用java技术体系搭建自己的系统,所以对java开发工程师以及java系统架构师的需求非常的多,虽然普遍的要求都是需要熟悉各种java开发框架(如目前比较流行ssi或者ssh框架),但是对于java语言本身的理解才是本质。如果你熟悉jvm原理以及jdk本身的实现,我相信对于其他开发框架的学习和深入理解应该不是很困难,因为很多灵活和高大山的框架都使用了jdk最核心 阅读详情

相关推荐

西门子200SMART自定义库开发实战:从PID到露点算法的工业应用

本文详细介绍了西门子200SMART自定义库开发实战,涵盖从PID控制到露点算法的工业应用。通过代码封装技巧、多语言支持和性能优化等高级开发方法,帮助工程师提升PLC编程效率。文章特别强调了自创库在实际项目中的优势,如恒温恒湿控制系统的成功案例,展示了自定义库在工业自动化中的强大应用价值。

lake5的博客 1024

OpenJDK源码赏析之二:java虚拟机启动流程到首函数调用全流程

看一个程序首先要找它的启动入口 OpenJDK的如下目录有着main程序的启动入口: 打开后是程序的入口,main的函数如下: int WINAPI WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow) { int margc; char** margv; const jboolean const_javaw = JNI_TRUE; __initenv = _envir..

星空_MAX 2230

STM32-CubeMx-HAL库-串口空闲中断+DMA——利用HAL_UARTEx_ReceiveToIdle_DMA实现不定长数据接收

STM32-CubeMx-HAL库-串口空闲中断+DMA——利用HAL_UARTEx_ReceiveToIdle_DMA实现不定长数据接收

weixin_43864631的博客 1万+

java主_Java主类的装载

在JavaMain()函数(定义在openjdk/jdk/src/share/bin/java.c文件中)中调用LoadMainClass()函数加载Java主类。LoadMainClass()函数的实现如下:源代码位置:openjdk/jdk/src/share/bin/java.c/** Loads a class and verifies that the main class is pre...

weixin_33393017的博客 292

移相变压器Simulink建模与HVDC系统仿真实践

移相变压器是电力电子领域实现精确相位调节的核心设备,其通过特殊绕组设计改变输出电压相位角,在解决环网潮流不均、阻尼功率振荡等场景具有关键作用。本文基于MATLAB/Simulink环境,详细解析移相变压器的建模原理与技术实现,包括磁路耦合特性模拟、参数计算方法和控制策略设计。针对HVDC高压直流输电和FACTS柔性交流输电系统等典型应用,提供仿真模型搭建技巧与问题排查指南,特别涵盖新能源并网场景下的相位调节优化方案。通过实测数据验证,所建模型在稳态精度和动态响应方面均满足工程要求,为电力系统稳定性分析提供有

weixin_28278377的博客 270

【STM32Cube_14】使用硬件I2C读写环境光强度传感器(BH1750)

本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件I2C外设读取环境光强度传感器数据(BH1750)

Mculover666的博客(嵌入式) 7240

eclipse java main 启动多次_启动一个没有 main 函数的 java 程序

天气不错,闲来无事,所以搞点事情吧...作为一名 JAVA 开发者,不知道大家有没有去想过,JAVA 程序为什么一定要从 main 函数执行开始,其实关于这个话题,我大概从网上搜了下,其实不乏有 main 方法是我们学习Java语言学习的第一个方法,也是每个 java 使用者最熟悉的方法, 每个 Java 应用程序都必须有且仅有一个 main 方法 这种说法。那么真的是这样吗?今天就来聊聊这个事情...

weixin_31613423的博客 745

【Unity3D开发小游戏】《打地鼠游戏》Unity开发教程

文章目录一、前言二、源码三、正文版本1、相机设置2、洞口设置3、洞口脚本4、鼹鼠5、鼹鼠动画6、鼹鼠碰撞器7、鼹鼠脚本8、击中鼹鼠的效果9、实现击中效果10、增加更多的洞口 一、前言 让我们使用Unity3D开发一个打地鼠游戏吧。 打地鼠游戏是一个非常有趣的街机游戏,是在1976年左右发明的。 游戏的主要玩法就是打击从洞里出来的鼹鼠,玩家击中鼹鼠的速度越快,得分就越高 我们将讲解制作游戏的所需的每...

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 8460

JVM进阶4--JVM启动过程源码流程分析

以openJDK8源码为基础,分析JVM启动过程,在openJDK中目录/openjdk/hotspot/src/share/tools/目录下有launcherjvm启动函数,而在openJDK8中没有启动函数,函数入口位于 /openjdk/jdk/src/share/bin/main.c 由于JVM运行环境不同,大致有windows有I及linux两种,因此JVM代码中有一部分是平台无...

大魔王 1823

PCL 将对象模板与点云对齐【2025最新版】

PCL模版匹配算法的使用案例,博客长期更新,本文最近更新时间为:2025年1月18日。

点云侠的博客 5378

华为OD机试 新系统真题-收集灵草(Java/Py/C++/Go/C/Js)

华为OD机试 新系统真题【收集灵草】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【收集灵草】多语言题解。

qq_45776114的博客 544

jvm启动流程

JVM对于初学者来说,一直比较难懂,最根本原因是它不够直观。 自己写了段代码,也正常运行了,都OK,没问题。到底是怎么运用JVM的,可能有一下的疑惑? 一:我也没有手动创建,它是如何创建的? 二:JVM在什么时候启动的? 三:JVM在什么时候关闭的? 带着问题我们继续往下看: 再回答问题之前,先看看我们是如何启动Java的。 1.我们在IDEA或者eclipse上面都有启动java程序的图标,如下图 2:直接打开cmd,再通过命令java -jar XXX.jar来启动应用。 下面来分析下到底是如何启动的

m0_67402731的博客 1905

PDD psnl_verification anti_content 生成顺序与环境校验说明

K不是明文 URL,而是从当前href再派生出来的一小段摘要值。页面 URL 变,K会跟着变但K不是直接肉眼可读的 URL 字串可以把它理解成“URL 的短摘要字段”。这一步是最容易被误解的地方。它吃进去的是压缩后的中间串不是直接吃环境字段它内部还带有长度预算 / 字符映射 / 位置处理逻辑所以最终看到的环境字段 bytes协议头deflate 压缩自定义编码多层叠加后的结果。先把字段总包做再把压缩结果转成raw再拼fTail最后走做字符级输出因此,当前看到的协议字段流。

码王吴彦祖的博客 68

jvm分析之一 jvm启动过程

jvm分析之一 jvm启动过程

cooldatabase 166

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

java jvm源码_JVM源码分析之JVM启动流程

原创申明:本文由公众号【猿灯塔】原创,转载请说明出处标注“365篇原创计划”第十四篇。今天呢!灯塔君跟大家讲:JVM源码分析之JVM启动流程前言:执行Java类的main方法,程序就能运行起来,main方法的背后,虚拟机究竟发生了什么?如果你对这个感兴趣,相信本文会给你一个答案,本文分析的openjdk版本为openjdk-7-fcs-src-b147-27classBootStrap{pub...

weixin_42322219的博客 363

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

JVM源码分析之JVM启动流程

原创申明:本文由公众号【猿灯塔】原创,转载请说明出处标注​ “365篇原创计划”第十四篇。 今天呢!灯塔君跟大家讲: JVM源码分析之JVM启动流程 前言: 执行Java类的main方法,程序就能运行起来,main方法的背后,虚拟机究竟发生了什么?如果你对这个感兴趣,相信本文会给你一个答案,本文分析的openjdk版本为openjdk-7-fcs-src-b147-27 classBootStrap{ publicstaticvoidmain(String[]arg...

猿灯塔的博客 300

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

jvm启动分析

最近比较闲,一直想学习下jvm是怎么运行的,所以搭建了一套环境分析分析。 目前环境为mac+xcode+jdk9,使用clang编译,clang版本clang-900.0.39.2。 总体流程 jdk总体分为lancher和jvm,jvm以动态链接库的形式被lancher加载。 lancher入口在jdk/src/java.base/share/native/launcher/main.c...

wuyu6394232的专栏 327

jvm源码分析之启动过程

这里介绍的是openjdk1.8的源码,分析jvm的启动过程,入口类main.c,入口方法main,动态库文件的加载等,创建过程jni.cpp->thread.cpp的调用过程

qwlhw的博客 758

Jvm-Sandbox原理分析-Sandbox的启动-01

Jvm-Sandbox的启动(一):sandbox.sh脚本分析 Sandbox的启动是通过其内置的shell脚本 sandbox.sh 开始执行的,一切的开始皆可从该脚本中探寻出结果。脚本有一定的代码量,大概有400+行,这里将该脚本分为如下几个部分进行讲解: 1、变量定义过程 这个过程首先预定义了接下来即将使用的一些变量。代码如下: # 定义sandbox的home目录,并为其赋值 typeset SANDBOX_HOME_DIR [[ -z ${SANDBOX_HOME_DIR} ]] &&

Mr_Xu12308的博客 1777

Spring Boot应用JVM参数配置对启动速度的影响分析

大家好,今天我们来聊聊 Spring Boot 应用 JVM 参数配置对启动速度的影响。JVM 参数的调优是一个迭代的过程,需要根据应用程序的实际情况进行调整。下面我们来分析一些关键的 JVM 参数,以及它们对 Spring Boot 应用启动速度的影响。要理解 JVM 参数的影响,首先需要了解 JVM 的启动过程。选择合适的 JVM 参数配置没有一劳永逸的方案。可以看到,通过合理的 JVM 参数配置,启动时间缩短了约 40%。每个阶段都可能受到 JVM 参数的影响,从而影响整体的启动速度。

weixin_41455464的博客 941

jvm启动代码分析

main函数在openjdk\jdk\src\share\bin\main.c文件中。简单流程分析如下: main->JLI_Launch 1.SelectVersion->LocateJRE,定位jre的位置。因为不同的操作系统上定位jre的方式不同,相关代码就和平台相关了,windows相关的一些代码在openjdk\jdk\src\windows下,而linux和solaris相...

cooldatabase 200

java 启动多个jvm_JVM原理分析,看了都说好

来自:月光夕颜链接:jianshu.com/p/be6f529160b6图片来自网络1 什么是JVM?JVM是Java Virtual Machine(Java虚拟机)的缩写,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成。JVM屏蔽了与操作系统平台相关的信息,使得Java程序只需要生成在Java虚拟机上...

weixin_39999859的博客 436

JVM进阶5--JVM启动过程JavaVMOption分析

JVM启动时,需要从java命令以及操作系统读取一系列配置参数来进行JVM创建工作。 JVM参数配置由结构体JavaVMOption来定义保存 /* * List of VM options to be specified when the VM is created. */ static JavaVMOption *options; static int numOptions, max...

大魔王 2851

JVM Profiler 启动过程分析

开篇  先来调侃一句,原来独角兽Uber的程序员写的代码也是看得懂的,而且还是比较容易看得懂的,所以有时候在设计模式和代码结构清晰以及可读性方面我还是更倾向于后者,宁可重复或浪费一部分代码也要整个代码的可读性更强一些。  整个JVM Profiler的启动过程比较简单也非常清晰,当我们通过下面命令启动Prof...

weixin_34061482的博客 334
上一篇: Java线程源码解析之yield和sleep
下一篇: 从jar包中读取资源文件
DViewer
博客等级 码龄16年 16粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值