`

HotspotVM的类型选择

阅读更多
前言

一般情况下,JDK中提供了Client和Server两种类型的JVM,那JDK是在运行时是如何选择的呢。本文主要探讨默认情况下Windows和Solaris(Linux)是如何选择JVM种类的。

JVM.cfg文件

在JRE_HOME/lib/<arch>(i386)/下存在这个一个jvm.cfg文件,用于配置JVM的种类。
/OpenJDK7/hotspot/src/share/tools/launcher/java.c 下的ReadKnownVMs函数注释详细的说明了该文件的主要格式:
    /*
     *     jvmcfg         :=  { vmLine }
1820 *     vmLine         :=  knownLine
1821 *                    |   aliasLine
1822 *                    |   warnLine
1823 *                    |   ignoreLine
1824 *                    |   errorLine
1825 *                    |   predicateLine
1826 *                    |   commentLine
1827 *     knownLine      :=  flag  "KNOWN"                  EOL
1828 *     warnLine       :=  flag  "WARN"                   EOL
1829 *     ignoreLine     :=  flag  "IGNORE"                 EOL
1830 *     errorLine      :=  flag  "ERROR"                  EOL
1831 *     aliasLine      :=  flag  "ALIASED_TO"       flag  EOL
1832 *     predicateLine  :=  flag  "IF_SERVER_CLASS"  flag  EOL
1833 *     commentLine    :=  "#" text                       EOL
1834 *     flag           :=  "-" identifier
     */



1.假如flag出现在knowLine行,那么identifier将作为存放JVM 库文件的路径名,去加载相应的VM;
2.假如flag出现在aliasLine行的第一个位置上,那么改行的第二个flag的identifier将作为JVM的名称;
3.假如flag出现在warnLine行的位置,那么该flag的identifier作为JVM的名称,但是会产生一条警告信息;
C:\Users\xingjl.fnst>D:\JDK\Oracle\jdk1.6.0_45\bin\java  -classic -version
Warning: classic VM not supported; client VM will be used
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) Client VM (build 20.45-b01, mixed mode)

4.假如flag出现在ignoreLine行的位置,那么该identifier将被忽略使用默认的VM。
5.假如flag出现在errorLine行的位置,那么错误消息将会生成。
C:\Users\xingjl.fnst>D:\JDK\Oracle\jdk1.6.0_45\bin\java  -error -version
Unrecognized option: -error
Could not create the Java virtual machine.

6.假如flag出现在predicateLine行,并且通过了机器上的判断(是否为服务器),那么predicateLine行的第二个flag的identifier将作为vm的名称;否则使用第一个。
7.如果在命令行中没有flag指定,那么jvm.cfg的文件的第一行将作为VM的名称。
8.PredicateLines这一行只可以作为jvm,cfg文件的第一行使用。
下面一个Windows JDK6u45的jvm.cfg文件的内容
-client KNOWN
-server KNOWN
-hotspot ALIASED_TO -client
-classic WARN
-native ERROR
-green ERROR

Lanuger启动流程

首先java.exe的CreateExecutionEnvironment函数调用GetJREPath去分析JRE的的安装路径,然后调用ReadKnownVMs函数去加载jvm.cfg文件,将文件中内容加载到如下的结构体中:
/* Values for vmdesc.flag */
#define VM_UNKNOWN              -1
#define VM_KNOWN                 0
#define VM_ALIASED_TO            1
#define VM_WARN                  2
#define VM_ERROR                 3
#define VM_IF_SERVER_CLASS       4
#define VM_IGNORE                5
struct vmdesc {
    char *name;
    int flag;
    char *alias;
    char *server_class;
};

其中flag为上面宏定义中定义的内容,name为jvm.cfg 文件中每行的第一个flag,当一行是aliasLine行时,aliasLine 则记录第二个falg的值;当一行为predicateLine 行时,server_class则记录第二flag的值。

加载完成后,调用CheckJvmType函数来确定当前所使用的VM种类;
命令行指定VM类型

1.命令行中,使用的是VM_KNOWN类型的(-client或-server),那么JVM将按照相应的路径加载jvm.dll
-client${ JAVA_HOME } \jre\bin\client\jvm.dll
-server${ JAVA_HOME } \jre\bin\server\jvm.dll

2.在命令行中,使用的是VM_ALIASED_TO(别名)类型的第一个flag时(-hotspot),那么使用VM_ALIASED_TO行的第二个flag作为vm的种类
while (knownVMs[jvmidx].flag == VM_ALIASED_TO) {
      int nextIdx = KnownVMIndex(knownVMs[jvmidx].alias);
–中略-
      jvmidx = nextIdx;
      jvmtype = knownVMs[jvmidx].name+1;
      loopCount++;
}

3.在命令行中,使用的是VM_WARN行内容,则先输出一条警告消息,然后使用jvm.cfg文件中的第一行falg作为VM类型
4.在命令行中,使用的是VM_IGNORE行内容,使用jvm.cfg文件中的第一行falg作为VM类型
5.在命令行中,使用的是VM_ERROR行内容,则会打印Error消息。
以下是3-5条的代码:
switch (knownVMs[jvmidx].flag) {
    case VM_WARN:
        if (!speculative) {
            fprintf(stderr, "Warning: %s VM not supported; %s VM will be used\n",
                    jvmtype, knownVMs[0].name + 1);
        }
        /* fall through */
    case VM_IGNORE:
        jvmtype = knownVMs[jvmidx=0].name + 1;
        /* fall through */
    case VM_KNOWN:
        break;
    case VM_ERROR:
        if (!speculative) {
            ReportErrorMessage2("Error: %s VM not supported", jvmtype, JNI_TRUE);
            exit(1);
        } else {
            return "ERROR";
        }
}

命令行未指定VM类型

在CheckJvmType函数中有如下代码:
if (jvmtype == NULL) {
      char* result = knownVMs[0].name+1;
      /* Use a different VM type if we are on a server class machine? */
      if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) &&
          (ServerClassMachine() == JNI_TRUE)) {
        result = knownVMs[0].server_class+1;
      }
      if (_launcher_debug) {
        printf("Default VM: %s\n", result);
      }
      return result;
}

由此可知,VM类型默认使用jvm.cfg第一行的flag。最终由该行的类型(是否为VM_IF_SERVER_CLASS)以及是否为服务器决定VM的类型。
Windows下:

JDK6u45的jvm.cfg文件参照上面提供的。
第一行非VM_IF_SERVER_CLASS类型,如果人为的修改为VM_IF_SERVER_CLASS类型,进行第二步的判断:是否为服务器级别的机器,Windows环境下的ServerClassMachine函数如下:
824jboolean
825ServerClassMachine() {
826  jboolean result = JNI_FALSE;
827#if   defined(NEVER_ACT_AS_SERVER_CLASS_MACHINE)
828  result = JNI_FALSE;
829#elif defined(ALWAYS_ACT_AS_SERVER_CLASS_MACHINE)
830  result = JNI_TRUE;
831#endif
832  return result;
833}

一般情况下总是返回false,所以,即使修改了cfg文件,VM种类也不会根据机器的配置进行自动搭配。
Solaris(Linux)

JDK6u45的jvm.cfg文件如下:
-client IF_SERVER_CLASS -server
-server KNOWN
-hotspot ALIASED_TO -client
-classic WARN
-native ERROR
-green ERROR

ServerClassMachine函数如下:
jboolean
1457ServerClassMachine(void) {
1458  jboolean result = JNI_FALSE;
1459#if   defined(NEVER_ACT_AS_SERVER_CLASS_MACHINE)
1460  result = JNI_FALSE;
1461#elif defined(ALWAYS_ACT_AS_SERVER_CLASS_MACHINE)
1462  result = JNI_TRUE;
1463#elif defined(__sun) && defined(__sparc)
1464  result = solaris_sparc_ServerClassMachine();
1465#elif defined(__sun) && defined(i586)
1466  result = solaris_i586_ServerClassMachine();
1467#elif defined(__linux__) && defined(i586)
1468  result = linux_i586_ServerClassMachine();
1469#else
1470  if (_launcher_debug) {
1471    printf("ServerClassMachine: returns default value of %s\n",
1472           (result == JNI_TRUE ? "true" : "false"));
1473  }
1474#endif
1475  return result;
1476}

我们以sun sparc平台的JDK为例,solaris_sparc_ServerClassMachine函数代码如下:
1102jboolean
1103solaris_sparc_ServerClassMachine(void) {
1104  jboolean            result            = JNI_FALSE;
1105  /* How big is a server class machine? */
1106  const unsigned long server_processors = 2UL;
1107  const uint64_t      server_memory     = 2UL * GB;
1108  const uint64_t      actual_memory     = physical_memory();
1109
1110  /* Is this a server class machine? */
1111  if (actual_memory >= server_memory) {
1112    const unsigned long actual_processors = physical_processors();
1113    if (actual_processors >= server_processors) {
1114      result = JNI_TRUE;
1115    }
1116  }
1117  if (_launcher_debug) {
1118    printf("solaris_" LIBARCHNAME "_ServerClassMachine: %s\n",
1119           (result == JNI_TRUE ? "JNI_TRUE" : "JNI_FALSE"));
1120  }
1121  return result;
1122}

如果机器的内存大于等于2GB,并且机器的CPU为2核或以上时,即判定为服务器级别的机器。
综合Widows和Solaris的分析,默认的VM种类选在如下:

1. 32位的JDK在Windows平台上,总是使用-client模式(即jvm.cfg文件中的第一个flag)
   默认第一个flag
  
   -client KNOWN
   

2. 32位的JDK在Solaris(Linux)机器上,根据机器是否为服务器级别的选择相应的VM;服务器级别的使用-sever,否则使用-client
   jvm.cfg默认的第一个falg
  
   -client IF_SERVER_CLASS -server 
   

3. 64位的JDK在Windows,Solaris平台上只有-server一种VM类型,可以选择-client但是      会被忽略。
  
   -client IGNORE
   

4. 64位的JDK在Linux平台上只有-server一种VM类型,选择-client会报错
  
   -client ERROR
   



-以上-
1
0
分享到:
评论

相关推荐

    J2ME学习文档

    - **ClassVM**和**HotSpotVM**分别在J2SE和J2EE中执行`JavaApplet`、`JavaServlet`或`JavaApplication`,其中HotSpotVM因高效而著称。 #### PersonalJava PersonalJava是一种基于J2ME CDC的规范,特别适合于具备...

    java8集合源码分析-Java-Virtual-Machine:Java-虚拟机

    源自知乎的一个问题,对于Java来说,所有类的父类都是Object类,但是Object类本身又属于类类型,即Class类型,那么问题就来了。 3. JVM简史 源自周老师的文章,讲述了JVM虚拟机的发展史,以及各种各样的Java虚拟机 4...

    java8集合源码分析-Java-Virtual-Machine:Java虚拟机资源汇总

    源自知乎的一个问题,对于Java来说,所有类的父类都是Object类,但是Object类本身又属于类类型,即Class类型,那么问题就来了。 3. JVM简史 源自周老师的文章,讲述了JVM虚拟机的发展史,以及各种各样的Java虚拟机 4...

    Java虚拟机笔记.pdf

    - **栈内存**:包括虚拟机栈和本地方法栈,用于支持Java方法和本地方法的执行,存放基本数据类型、对象引用等。 - **程序计数器**:用于指示当前线程所执行的字节码指令的位置,是“线程私有”的内存区域。 ### JVM...

    JVM内存区域图例说明.7z

    JVM内存区域主要分为线程...线程私有数据区域生命周期与线程相同,依赖用户线程的启动/结束而创建/销毁(在HotspotVM内,每个线程都与操作系统的本地线程直接映射,因此这部分内存区域的存/否跟随本地线程的生/死对应)。

    JVM高级特性之垃圾收集.pdf

    方法区(Method Area)则是各个线程共享的内存区域,用于存储类型信息、常量、静态变量等。运行时常量池(Runtime Constant Pool)作为方法区的一部分,存放了编译期生成的各种字面量与符号引用。 垃圾收集的过程...

    深入理解Java虚拟机视频教程(jvm性能调优+内存模型+虚拟机原理)视频教程

    第14节Java虚拟机-HotSpotVM00:04:23分钟 | 第15节Java虚拟机-kvm00:03:04分钟 | 第16节Java虚拟机-JRockit00:04:12分钟 | 第17节Java虚拟机-j900:04:23分钟 | 第18节Java虚拟机-dalvik00:02:20分钟 | 第19节...

    深入理解JVM内存结构及运行原理全套视频加资料.txt

     第14讲 Java虚拟机-HotSpotVM 00:04:23  第15讲 Java虚拟机-kvm 00:03:04  第16讲 Java虚拟机-JRockit 00:04:12  第17讲 Java虚拟机-j9 00:04:23  第18讲 Java虚拟机-dalvik 00:02:20  第19讲 Java...

Global site tag (gtag.js) - Google Analytics