从JDK源码级深入剖析main方法的运行机制
如果你是一名Java应用开发工程师,你应该对“public static void main(String[] args)”这段代码再熟悉不过了,然而你是否了解main方法是如何调用的,为什么我们运行java.exe,就能启动应用程序?下面,让我们来一探究竟吧!
首先,聊一聊,java.exe文件是怎么来的
如果你下载了OpenJDK源码,在源码目录src\java.base\share\native\libjli目录下有java.c这样一个文件,java.exe文件是通过编译java.c文件生成的可执行文件。java.c文件是Java Runtime Environment(JRE)的一部分,它是用C语言编写的,用于启动Java应用程序并运行Java字节码。
其次,讲一讲,运行java.exe后发生了什么
在java.c文件当中,有这样一个方法:
/*
* Entry point.
*/
JNIEXPORT int JNICALL
JLI_Launch(int argc, char ** argv, /* main argc, argv */
int jargc, const char** jargv, /* java args */
int appclassc, const char** appclassv, /* app classpath */
const char* fullversion, /* full version defined */
const char* dotversion, /* UNUSED 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 /* unused */
)
这个方法是Java虚拟机的入口点,负责解析命令行参数、加载Java应用程序并启动Java虚拟机。在JLI_Launch方法中,会解析命令行参数,包括指定Java类路径、指定JVM参数等,然后调用JVM的启动函数,启动Java虚拟机并加载Java应用程序。也就是说,当你运行“java.exe YourClassName”这个命令时,调用的就是JLI_Launch这个方法。
接着,看一看,JLI_Launch这个方法做了哪些事情
我们进入方法内部,我们看到方法的最后一行代码:
return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret);
该代码作用是对Java虚拟机进行初始化,如果你现在是windows系统中运行java应用程序,那么该方法的实现是在src\java.base\windows\native\libjli\java_md.c这个文件中:
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);
}
我们继续进入ContinueInNewThread这个方法,发现了
rslt = CallJavaMainInNewThread(threadStackSize, (void*)&args);
这段代码,继续进入CallJavaMainInNewThread,找到了这段代码
rslt = JavaMain(args);
因此我们知道了:Java类中的main方法public static void main(String[] args),就是由java.c文件中JavaMain方法调用的。
接着,瞧一瞧,JavaMain这个方法是如何调用main方法的
上代码:
int JavaMain(void* _args)
{
JavaMainArgs *args = (JavaMainArgs *)_args;
...
//初始化Java虚拟机
if (!InitializeJVM(&vm, &env, &ifn)) {
JLI_ReportErrorMessage(JVM_ERROR1);
exit(1);
}
...
//加载主运行类
mainClass = LoadMainClass(env, mode, what);
CHECK_EXCEPTION_NULL_LEAVE(mainClass);
...
//通过加载的主运行类,获取main方法
mainID = (*env)->GetStaticMethodID(env, mainClass,"main","([Ljava/lang/String;)V");
CHECK_EXCEPTION_NULL_LEAVE(mainID);
//调用main函数
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
...
}
这里可能就有读者要问了,C程序是怎么调用Java程序的?
实际上,通过JNI(java本地接口,是Java Native Interface的缩写)技术可以实现C语言调用Java,JNI是Java平台提供的一种编程框架,用于实现Java应用程序与本地(非Java)应用程序之间的相互调用。JNI提供了一组规范和工具,使Java应用程序能够调用C、C++和其他本地语言编写的代码,反之亦然。通过JNI,Java程序员可以利用现有的本地代码库,并与其他本地应用程序进行交互,从而扩展Java应用程序的功能和性能。
最后,我们用流程图总结一下

从JDK源码级深入剖析main方法的运行机制的更多相关文章
- 源码级强力分析hadoop的RPC机制
分析对象: hadoop版本:hadoop 0.20.203.0 必备技术点: 1. 动态代理(参考 :http://weixiaolu.iteye.com/blog/1477774 )2. Java ...
- jdk源码剖析:Synchronized
开启正文之前,先说一下源码剖析这一系列,就以"死磕到底"的精神贯彻始终,最少追踪到JVM指令(再往下C语言实现了). =========正文分割线=========== Sync ...
- jdk源码剖析三:锁Synchronized
一.Synchronized作用 (1)确保线程互斥的访问同步代码 (2)保证共享变量的修改能够及时可见 (3)有效解决重排序问题.(Synchronized同步中的代码JVM不会轻易优化重排序) 二 ...
- 从JDK源码角度看java并发的原子性如何保证
JDK源码中,在研究AQS框架时,会发现很多地方都使用了CAS操作,在并发实现中CAS操作必须具备原子性,而且是硬件级别的原子性,java被隔离在硬件之上,明显力不从心,这时为了能直接操作操作系统层面 ...
- 【Java编程实战】Metasploit_Java后门运行原理分析以及实现源码级免杀与JRE精简化
QQ:3496925334 文章作者:MG1937 CNBLOG博客ID:ALDYS4 未经许可,禁止转载 某日午睡,迷迷糊糊梦到Metasploit里有个Java平台的远控载荷,梦醒后,打开虚拟机, ...
- Timer的故事----Jdk源码解读
咱们今天也来说说定时器Timer Timer是什么? Timer n. [电子] 定时器:计时器:计时员 从翻译来看,我们可以知道Timer的本意是,定时定点. 而JDK中Timer类也的确是这个本 ...
- MapReduce的MapTask任务的运行源码级分析
TaskTracker任务初始化及启动task源码级分析 这篇文章中分析了任务的启动,每个task都会使用一个进程占用一个JVM来执行,org.apache.hadoop.mapred.Child方法 ...
- TaskTracker任务初始化及启动task源码级分析
在监听器初始化Job.JobTracker相应TaskTracker心跳.调度器分配task源码级分析中我们分析的Tasktracker发送心跳的机制,这一节我们分析TaskTracker接受JobT ...
- JDK源码学习--String篇(二) 关于String采用final修饰的思考
JDK源码学习String篇中,有一处错误,String类用final[不能被改变的]修饰,而我却写成静态的,感谢CTO-淼淼的指正. 风一样的码农提出的String为何采用final的设计,阅读JD ...
- JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue
JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue 目的:本文通过分析JDK源码来对比ArrayBlockingQueue 和LinkedBlocki ...
随机推荐
- 一文快速入门任务调度框架-Quartz
前言 还不会 Quartz?如果你还没有接触过Quartz,那么你可能错过了一个很棒的任务调度框架!Quartz 提供了一种灵活.可靠的方式来管理和执行定时任务,让咱们的定时任务更加优雅.本篇文章将为 ...
- 系统评价——理想点TOPSIS法的R语言实现(五)
TOPSIS 法是一种常用的综合评价方法,能充分利用原始数据的信息,其结果能精确地反映各评价方案之间的差距.TOPSIS全称Technique for Order Preference by Simi ...
- Redis(一)五种基本数据类型
1 NoSQl数据库 1.1 技术的发展 技术的分类: ①解决功能性问题:javase ②解决扩展性问题:框架 ③解决性能问题:redis 1.2 NoSQL数据库概述 NoSQL(Not Only ...
- SPI-SPI主机硬件片选功能使用说明
SPI主机硬件片选功能使用说明 SPI协议最早的标准,是由摩托罗拉公司制定.在协议使用的过程中,根据实际需求可能会进行一些扩展和修改. 在一份由飞思卡尔半导体发布的SPI V4.01版本规范中,对片选 ...
- Linux rsyslogd服务学习
本篇笔记来自该博客: http://c.biancheng.net/view/1097.html 服务简介 在CentOS 6.x 中日志服务已经由 rsyslogd 取代了原先的 syslogd.r ...
- Sitecore10 Demo演示环境Azure一键部署(Step By Step Guide to installing Sitecore10 in Azure Paas)
本文演示Sitecore XP Single(XP0)在Azure上的一键部署,即"30分钟生成Sitecore演示环境"的一环. 关于XP(即Sitecore Experienc ...
- Caused by: java.net.BindException: Address already in use: JVM_Bind(ActiveMq已经启动)
1.本地启动项目开启两个启动类出错. Error creating bean with name 'brokerService' defined in class path resource [com ...
- vue3.0
https://www.yuque.com/gdnnth/vue-v3 http://www.liulongbin.top:8085/#/ https://www.yuque.com/woniuppp ...
- MySQL高频面试题
什么是MySQL MySQL是一个关系型数据库,它采用表的形式来存储数据.你可以理解成是Excel表格,既然是表的形式存储数据,就有表结构(行和列).行代表每一行数据,列代表该行中的每个值.列上的值是 ...
- 【Ubuntu】1. 创建虚拟机
这一篇主要写了虚拟机的创建,不包含操作系统的安装,中间有些步骤没有提到的根据默认操作即可,也可以根据个人情况设置. 点击创建新的虚拟机 这一步可以选择典型安装,过程更简单些,这里我选择自定义. 在安装 ...