HotspotVM的类型选择
程序员文章站
2022-07-15 14:52:50
...
前言
一般情况下,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
-以上-
推荐阅读
-
什么牌子的奶粉好,宝妈们知道怎么选择奶粉吗!
-
腾讯手游助手如何选择微信登录 微信登录腾讯手游模拟器的方法介绍
-
解决无法在unicode和非unicode字符串数据类型之间转换的方法详解
-
实例讲解iOS应用开发中UIPickerView滚动选择栏的用法
-
谷歌输入法模糊拼音设置根据习惯选择容易混淆的模糊音
-
完美解决PJ的Cookies保存时限问题!可选择记录登陆时长!
-
从零开始的PYTHON3 windows如何运行python,编辑器选择
-
你的企业选择微博营销了吗?其实原因很简单
-
select标签设置默认值选择(select设置初始值的方法)
-
uniqueidentifier转换成varchar数据类型的sql语句