转贴:jvm 的工作原理和特点 (一些二逼的逼神面试官会问的问题)

了解下 jvm 的工作原理

     ps:(一些二逼的逼神面试官会问的问题)

jvm 工作原理和特点主要是指操作系统装入 jvm 是通过 jdk 中 java.exe 来完成,通过以下 4 步来加载 jvm 环境。

1.创建 jvm  加环境和配置

2.加载 jvm .dll

3.初始化 jvm .dll 并挂接到 jnienv (jni 调用接口) 实例

4.调用 jnienv 实例加载并处理 class 类。

在我们执行和调试 Java 程序的时,常常会提到一个 jvm 的概念. jvm 是 Java 程序执行的环境,它是同时是一个操作系统的一个应用程序一个进程,因此它也有他自己运行的生命周期,也有自己的代码和数据空间.

首先来说一下 jvm 工作原理中的 jdk.它在整个 Java 体系中充当着什么角色呢?

我非常惊叹 sun 公司大师们的设计天才,能把一个如此完整的体系结构化得如此完美.jdk 在这个体系中充当一个生产加工中心,产生全部的数据输出,是全部指令和策略的运行中心.它本身提供了 Java 的完整方案,能够开发目前 Java 能支持的全部应用和系统程序.jdk 除了 JVM 之外,另一些核心的 API,集成 API,用户工具,开发技术,开发工具和 API 等组成.

JVM 在整个 jdk 中处于最底层,负责与操作系统的交互,用来屏蔽操作系统环境,提供一个完整的 Java 执行环境,因此也就相当于是一台虚拟计算机. 操作系统装入 JVM 是通过 jdk 中 Java.exe 来完成,通过以下4步来加载 JVM 环境.

1.创建 JVM 加载环境和配置

2.装载 JVM.dll

3.初始化 JVM.dll 并挂接到 JNIEnv (JNI调用接口) 实例

4.调用 JNIEnv 实例加载并处理 class 类。

一.JVM 加载环境,JVM 提供的方式是操作系统的动态连接文件

既然是文件那就有一个加载路径的问题,Java 是怎么找这个路径的呢?当你在调用 Java test 的时候,操作系统会在 path 下找到 Java.exe 程序,Java.exe 就通过以下一个过程来确定 JVM 的路径和相关的参数配置。以下是 Windows 的实现的分析:

首先查找 jre 路径,Java 通过 GetApplicationHome api 来获得当前的 Java.exe 的绝对路径。C:\jdk1.7\bin\Java.exe,那么它会取到绝对路径 c:\jdk1.7,判断 c:\jdk1.7\bin\Java.dll 文件是否存在,假设存在就把 c:\jdk1.7 作为 jre 路径,如果不存在就判断c:\jdk1.7\jre\bin\Java.dll 是否存在,如果存在,就把 c:\jdk1.7\jre 作为 jre 路径。如果不存在,就调用 GetPublicJREHome 查HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment\“当前 JRE 的版本”\JavaHome 的路径作为 jre 路径。

然后装载 JVM.cfg 文件 JRE 路径+\lib+\ARCH(CPU构架)+\JVM.cfg ARCH(CPU构架)的判断是通过Java_md.c 中 GetArch函数实现的。这个函数中 windows 平台仅仅有两种情况:WIN64 的 ‘ia64’,其它情况都为 ‘i386’。

示例:C:\jdk1.7\jre\lib\i386\JVM.cfg。基本内容如下:

  1. -client KNOWN   
  2. -server KNOWN   
  3. -hotspot ALIASED_TO -client   
  4. -classic WARN   
  5. -native ERROR   
  6. -green ERROR  

在我们的jdk文件夹中jre\bin\server和jre\bin\client都有JVM.dll文件存在。而Java正是通过JVM.cfg配置文件来管理这些不同版本号的JVM.dll的.通过文件我们能够定义眼下jdk中支持那些JVM,前面部分(client)是JVM名称。后面是參数,KNOWN表示JVM存在,ALIASED_TO表示给别的JVM取一个别名。WARN表示不存在时找一个JVM替代,ERROR表示不存在抛出异常.在执行Java XXX是,Java.exe会通过CheckJVMType来检查当前的JVM类型。Java能够通过两种參数的方式来指定详细的JVM类型。一种依照JVM.cfg文件里的JVM名称指定,另外一种方法是直接指定,它们执行的方法各自是“Java -J”、“Java -XXaltJVM=”或“Java -J-XXaltJVM=”。

假设是第一种參数传递方式。CheckJVMType函数会取參数‘-J’后面的JVM名称,然后从已知的JVM配置參数中查找假设找到同名的则去掉该JVM名称前的‘-’直接返回该值。而另外一种方法,会直接返回“-XXaltJVM=”或“-J-XXaltJVM=”后面的JVM类型名称;假设在执行Java时未指定上面两种方法中的任一一种參数。CheckJVMType会取配置文件里第一个配置中的JVM名称,去掉名称前面的‘-’返回该值。CheckJVMType函数的这个返回值会在以下的函数中汇同jre路径组合成JVM.dll的绝对路径。假设没有指定这会使用JVM.cfg中第一个定义的JVM.能够通过set _Java_LAUNCHER_DEBUG=1在控制台上測试.

最后获得JVM.dll的路径,JRE路径+\bin+\JVM类型字符串+\JVM.dll就是JVM的文件路径了。可是假设在调用Java程序时用-XXaltJVM=參数指定的路径path,就直接用path+\JVM.dll文件做为JVM.dll的文件路径.

二:装载 JVM.dll

通过第一步已经找到了JVM的路径,Java通过LoadJavaVM来装入JVM.dll文件.装入工作非常easy就是调用Windows API函数:

LoadLibrary装载JVM.dll动态连接库.然后把JVM.dll中的导出函数JNI_CreateJavaVM和JNI_GetDefaultJavaVMInitArgs挂接到InvocationFunctions变量的CreateJavaVM和GetDefaultJavaVMInitArgs函数指针变量上。

JVM.dll的装载工作宣告完毕。

三:初始化 JVM。获得本地调用接口。这样就能够在Java中调用JVM的函数了.调用InvocationFunctions->CreateJavaVM也就是JVM中JNI_CreateJavaVM方法获得JNIEnv结构的实例.

四:执行 Java 程序。

Java程序有两种方式一种是jar包,一种是class. 执行jar,Java -jar XXX.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主类中

“public static void main(String[] args)”方法,并推断该方法是否为public方法。然后调用JNIEnv实例的

CallStaticVoidMethod方法调用该Java类的main方法。 

原文: www.cnblogs.com/mengfanrong/p/5225506.html

猜你喜欢

转载自blog.csdn.net/beguile/article/details/86765139
今日推荐