控制台程序的运行少不了要通过控制台来传递参数,譬如:
Sh代码
ls -la
这是shell脚本的常用命令,其就是通过后置参数来传递相关信息。UNIX环境为C语言中提供了getopt()这样的函数可以解析后置参数,这个函数是很实用很强大的,但Java就...(我Google了一下,倒没有怎么找出来)。大概是这个功能对Java来说太不足挂齿了吧,但总得有个解决方法才行。
下面就是一个代码实例,用以说明。
这个实例运行的结果是运行在控制台,并允许可选的输入参数:
Sh代码
java TestOpt -i 89 -b -s TestString
那么就会设置几个prarameter的值
Java代码
public class TestOpt {
public static void main(String[] args) {
/*
* 这里先取默认值,因为不是所有参数都会被用户提供
*/
boolean prarameter1 = false
int prarameter2 = 0
String prarameter3 = ""
/*
* 设置一个offset变量,用来定位相关信息
*/
int optSetting = 0
for (optSetting <args.lengthoptSetting++) {
if ("-b".equals(args[optSetting])) {
prarameter1 = true
} else if ("-i".equals(args[optSetting])) {
prarameter2 = Integer.parseInt(args[++optSetting])
} else if ("-s".equals(args[optSetting])) {
prarameter3 = args[++optSetting]
}
}
/*
* 这里我只是打印出来相关的设置信息,具体的行为肯定是要自己取定义打
*/
System.out.println(prarameter1)
System.out.println(prarameter2)
System.out.println(prarameter3)
}
}
这种类似的方法估计应该有很多吧,但这个应该算是比较轻量级的。当然若参数非常多(同时也得进行验证输入)
在hotspot/src/share/vm/runtime/globals.hpp以及各组件、平台相关的*_gloabals.hpp有这些VM参数的声明,然后在对应的cpp文件里有它们的实现。
在product build中,被宏展开之后实际上会变成:
在JavaMain()函数中会创建虚机:
创建虚拟机的函数中,首先会进行虚拟机参数解析并设置好相应的全局变量的值,例如UseParallelGC。然后在init_globals()中就会根据UseParallelGC在创建堆设置好GC回收策略。
parse_each_vm_init_arg会遍历获取到的参数列表,然后根据各参数进行相应的设置和赋值。-XX:+UseParallelGC最后会调用process_argument(tail, args->ignoreUnrecognized, origin)进行设置。
Flag的数据结构(runtime/globas.hpp):
flagTable这个Flag数组记录了VM参数的名字与存储位置(地址)之间的对应关系。于是通过它就可以实现从字符串到实际全局变量的赋值。
遍历flagTable找到名字所指定的Flag:
然后通过Flag里记录的地址给VM参数对应的全局变量赋值:
在Universe::create_heap()中会根据前面解析出来的堆相关参数,进而创建所需要的堆,并设置相应的GC回收策略。
查找"JavaMain"在哪个文件中:
grep -rn "JavaMain" jdk/src/
查找"Threads::create_vm"方法在哪个文件中:
grep -rn "Threads::create_vm" hotspot/
查找Arguments::parse
查找"Universe::initialize_heap"