先不讲java虚拟机,我们从最最基本的出发。
当我开始学习java之初,老是听我老师吹牛逼说java能跨平台,如何如何厉害,我一直有疑问,java可以跨平台,别的就不行?很惭愧,现在才正式开始总结一下:
1.、java是如何做到跨平台的,为什么有了JDK,JRE就能跨平台
2、为什么tomcat能在各个平台运行,靠的是啥,为啥运行之后访问的东西都是一样的,不会有linux和window的区别?
以下以windows平台为例
【解决第一个问题:为什么有了JDK、JRE,就能跨平台】
首先我们先了解下进程的概念:
第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。----来自百度百科
第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。
为什么要先了解进程的概念,在我的理解来看java虚拟机就是一个进程。
然后我们在看问题,JDK和JRE分别是什么作用:最简单的理解,JDK就是个工具包,JRE全称Java runtime enviroment,java运行时环境。
jre既然是java运行环境,那么环境是怎么产生的呢?
表面上看,执行java.exe就产生了JVM,其实可以分为四步:
1.执行代码时(如JAVATEST),操作系统会查找java.exe程序,具体执行过程,先执行方法CreateExcutionEnvironment(java_md.c),在这个方法中,根据GetApplicationHome查找你的java.exe所在目录,然后截取目录c:/program/java/jdk/bin,并查找java.dll是否在此目录中,如果存在就把c:/program/java/jdk作为jre路径,如果不存在则判断c:/program/java/jdk/jre/bin/java.dll是否存在,如果存在则把c:/program/java/jdk/jre作为路径,如果不存在,则调用GetPublicJREHome查HKEY_LOCAL_MACHINE/Software/JavaSoft/JavaRuntimeEnvironment/“当前JRE版本号”/JavaHome的路径为jre路径。
其次,我们要找到相应的jvm.cfg,确定要使用哪个jvm.dll,因为在我们的jdk目录中jre/bin/server和jre/bin/client都有JVM.dll文件,所以我们从JRE路径+/lib+/ARCH(CPU构架)+/JVM.cfg找到配置文件。CPU架构ARCH是在java_md.c中getArch方法判断的,里面只有两个分支,一个是64为的,一个是X86。找到jvm.cfg之后,我们就可以确定要使用哪个jvm.dll。
2.找到jvm.dll之后,就开始载入JVM.dll,里面是C代码(dll为动态链接库文件:含义为程序共享执行特殊任务所必需的代码和资源。白话:调用系统资源,调用系统API),具体载入方法为通过LoadJavaVM(具体实现在java_md.c,line365,里面包含了createJavaVM,以及获取jvm初始化参数的方法)。装入工作很简单就是调用WindowsAPI函数:LoadLibary装载jvm.dll动态链接库,然后吧jvm.dll中的导出函数jni_createjavavm和jni_getDefaultjavavminitargs挂接到invocationFunctions变量的CraeteJavaVm和GetDefaultJavaVMInitargs函数指针变量上。
3.初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例。如果jvm要调用内部代码,需要JNIEnv(包含了本地window函数的接口),jvm如果要调用的话,需要在C或者C++代码中申明。
4.调用JNIEnv实例装载并处理class类。这里必须要说一下,怎么运行java程序,一种是class运行,一种是jar。java.exe调用GetMainClassName函数,该函数先获得JNIEnv实例然后调用java类,
Java.util.jar.JarFileJNIEnv中方法getManifest()并从返回的Manifest对象中取getAttributes("Main-Class")的值即jar包中文件:META-INF/MANIFEST.MF指定的Main-Class的主类名作为运行的主类。之后main函数会调用Java.c中LoadClass方法装载该主类(使用JNIEnv实例的FindClass)。main函数直接调用Java.c中LoadClass方法装载该类。如果是执行class方法。main函数直接调用Java.c中LoadClass方法装载该类。
然后main函数调用JNIEnv实例的GetStaticMethodID方法查找装载的class主类中
“publicstaticvoidmain(String[]args)”方法,并判断该方法是否为public方法,然后调用JNIEnv实例的
CallStaticVoidMethod方法调用该Java类的main方法。
---------------------
参考:https://blog.csdn.net/wyt4455/article/details/8717328