在hotspot/src/share/vm/runtime/globals.hpp以及各组件、平台相关的*_gloabals.hpp有这些VM参数的声明,然后在对应的cpp文件里有它们的实现。
product(bool, UseParallelGC, false, \
"Use the Parallel Scavenge garbage collector")
在product build中,被宏展开之后实际上会变成:
extern "C" bool UseParallelGC; // from DECLARE_PRODUCT_FLAG
// globals.cpp
// define the VM flag
bool UseParallelGC = false; // from MATERIALIZE_PRODUCT_FLAG
// keep all VM flags in a table
static Flag flagTable[] = {
// ...
{ "bool", "UseParallelGC", &UseParallelGC, "{product}", DEFAULT }, // from RUNTIME_PRODUCT_FLAG_STRUCT
// ...
{0, NULL, NULL}
};
Flag* Flag::flags = flagTable;
// globals_extension.hpp
// the two enums below are used to index into the flags table
typedef enum {
// ...
Flag_UseParallelGC
// ...
} CommandLineFlag;
typedef enum {
// ...
Flag_UseParallelGC_bool
// ...
} CommandLineFlagWithType;
在JavaMain()函数中会创建虚机:
int JNICALL
JavaMain(void * _args)
{
...
/* Initialize the virtual machine */
start = CounterGet();
if (!InitializeJVM(&vm, &env, &ifn)) {
JLI_ReportErrorMessage(JVM_ERROR1);
exit(1);
}
...
}
创建虚拟机的函数中,首先会进行虚拟机参数解析并设置好相应的全局变量的值,例如UseParallelGC。然后在init_globals()中就会根据UseParallelGC在创建堆设置好GC回收策略。
jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
...
// Parse arguments
jint parse_result = Arguments::parse(args);
...
// Initialize global modules
jint status = init_globals();
...
}
1.解析参数
jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, Flag::Flags origin) {
// iterate over arguments
for (int index = 0; index < args->nOptions; index++) {
const JavaVMOption* option = args->options + index;
if (match_option(option, "-verbose", &tail)) {
} else if (match_option(option, "-Xmn", &tail)) {
} else if (match_option(option, "-Xms", &tail)) {
} else if (match_option(option, "-Xmx", &tail) || match_option(option, "-XX:MaxHeapSize=", &tail)) {
} else if (match_option(option, "-D", &tail)) {
} else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx
// Skip -XX:Flags= and -XX:VMOptionsFile= since those cases have
// already been handled
if ((strncmp(tail, "Flags=", strlen("Flags=")) != 0) &&
(strncmp(tail, "VMOptionsFile=", strlen("VMOptionsFile=")) != 0)) {
if (!process_argument(tail, args->ignoreUnrecognized, origin)) {
return JNI_EINVAL;
}
}
}
}
}
parse_each_vm_init_arg会遍历获取到的参数列表,然后根据各参数进行相应的设置和赋值。-XX:+UseParallelGC最后会调用process_argument(tail, args->ignoreUnrecognized, origin)进行设置。
Flag的数据结构(runtime/globas.hpp):
struct Flag {
const char* _type;
const char* _name;
void* _addr;
NOT_PRODUCT(const char* _doc;)
Flags _flags;
// points to all Flags static array
static Flag* flags;
// number of flags
static size_t numFlags;
}
Flag::Error CommandLineFlags::boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
return boolAtPut(result, value, origin);
}
flagTable这个Flag数组记录了VM参数的名字与存储位置(地址)之间的对应关系。于是通过它就可以实现从字符串到实际全局变量的赋值。
遍历flagTable找到名字所指定的Flag:
// Search the flag table for a named flag
Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked, bool return_flag) {
for (Flag* current = &flagTable[0]; current->_name != NULL; current++) {
if (str_equal(current->_name, name, length)) {
// Found a matching entry.
// Don't report notproduct and develop flags in product builds.
if (current->is_constant_in_binary()) {
return (return_flag ? current : NULL);
}
// Report locked flags only if allowed.
if (!(current->is_unlocked() || current->is_unlocker())) {
if (!allow_locked) {
// disable use of locked flags, e.g. diagnostic, experimental,
// commercial... until they are explicitly unlocked
return NULL;
}
}
return current;
}
}
// Flag name is not in the flag table
return NULL;
}
然后通过Flag里记录的地址给VM参数对应的全局变量赋值:
Flag::Error CommandLineFlags::boolAtPut(Flag* flag, bool* value, Flag::Flags origin) {
const char* name;
if (flag == NULL) return Flag::INVALID_FLAG;
if (!flag->is_bool()) return Flag::WRONG_FORMAT;
name = flag->_name;
Flag::Error check = apply_constraint_and_check_range_bool(name, *value, !CommandLineFlagConstraintList::validated_after_ergo());
if (check != Flag::SUCCESS) return check;
bool old_value = flag->get_bool();
trace_flag_changed(name, old_value, *value, origin);
check = flag->set_bool(*value);
*value = old_value;
flag->set_origin(origin);
return check;
}
2.使用UseParallelGC参数
CollectedHeap* Universe::create_heap() {
assert(_collectedHeap == NULL, "Heap already created");
#if !INCLUDE_ALL_GCS
if (UseParallelGC) {
fatal("UseParallelGC not supported in this VM.");
} else if (UseG1GC) {
fatal("UseG1GC not supported in this VM.");
} else if (UseConcMarkSweepGC) {
fatal("UseConcMarkSweepGC not supported in this VM.");
#else
if (UseParallelGC) {
return Universe::create_heap_with_policy();
} else if (UseG1GC) {
return Universe::create_heap_with_policy();
} else if (UseConcMarkSweepGC) {
return Universe::create_heap_with_policy();
#endif
} else if (UseSerialGC) {
return Universe::create_heap_with_policy();
}
ShouldNotReachHere();
return NULL;
}
在Universe::create_heap()中会根据前面解析出来的堆相关参数,进而创建所需要的堆,并设置相应的GC回收策略。
3.附录
查找"JavaMain"在哪个文件中:
grep -rn "JavaMain" jdk/src/
root@wz-All-Series:/home/wz/openjdk/openjdk-jdk9-jdk9# grep -rn "JavaMain" jdk/src/
jdk/src/java.base/share/native/libjli/java.h:223:int JNICALL JavaMain(void * args); /* entry point */
jdk/src/java.base/share/native/libjli/java.c:386:JavaMain(void * _args)
jdk/src/java.base/share/native/libjli/java.c:2313: rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args);
jdk/src/java.base/macosx/native/libjli/java_md_macosx.c:1057: rslt = JavaMain(&args)
查找"Threads::create_vm"方法在哪个文件中:
grep -rn "Threads::create_vm" hotspot/
root@wz-All-Series:/home/wz/openjdk/openjdk-jdk9-jdk9# grep -rn "Threads::create_vm" hotspot/
hotspot/src/share/vm/runtime/thread.cpp:3500:jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
查找Arguments::parse
wz@wz-All-Series:~/openjdk/openjdk-jdk9-jdk9/hotspot$ grep -rn "Arguments::parse(" .
./src/share/vm/runtime/arguments.cpp:4311:jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) {
查找"Universe::initialize_heap"
root@wz-All-Series:/home/wz/openjdk/openjdk-jdk9-jdk9# grep -rn "Universe::initialize_heap" hotspot/
hotspot/src/share/vm/memory/universe.cpp:754:jint Universe::initialize_heap() {
参考
- 求问JVM参数解析问题