学习源码,是代码技术提升的一个重要手段,在java相关的内容中,有各类框架的源码、tomcat的源码、android源码、jdk标准库的源码和jvm的源码等各种值得学习的内容。在这些内容当中,jvm的源码是唯一一种纯用c、c++完成的,因此对于很多写习惯了java的程序员来说,阅读jvm是一件不那么容易的事情,而且目前大多数的jvm源码相当冗长,不易于阅读,所以为了简单的了解jvm的运行机制,我们选择了“麻雀虽小,五脏俱全”的jamvm来进行阅读。
首先,下载编译jamvm自行百度去,这篇文章只对jamvm的代码做简单理解
由于对jamvm还不是特别了解,我们简单地从主函数开始进行阅读
int main(int argc, char *argv[]) {
Class *array_class, *main_class;
Object *system_loader, *array;
MethodBlock *mb;
InitArgs args;
int class_arg;
char *cpntr;
int status;
int i;
setDefaultInitArgs(&args);
// 解析命令参数
class_arg = parseCommandLine(argc, argv, &args);
// 设置类栈
args.main_stack_base = &array_class;
if (!initVM(&args)) {
/**
* TODO: Read
* 启动虚拟机, 失败打印
*/
printf("Could not initialise VM. Aborting.\n");
exit(1);
}
if ((system_loader = getSystemClassLoader()) == NULL)
// TODO 设置主classLoader
goto error;
// TODO 给主线程设置classLoader
mainThreadSetContextClassLoader(system_loader);
for (cpntr = argv[class_arg]; *cpntr; cpntr++)
/**
* 把class的参数, 如‘jamVM HelloWorld’的‘HelloWorld’赋值给cpntr,对于路径修改为斜杠
*/
if (*cpntr == '.')
*cpntr = '/';
// TODO 查询主函数
main_class = findClassFromClassLoader(argv[class_arg], system_loader);
if (main_class != NULL)
// TODO 初始化一个主函数
initClass(main_class);
if (exceptionOccurred())
// TODO 大概是处理异常
goto error;
// TODO 下面一整段
mb = lookupMethod(main_class, SYMBOL(main),
SYMBOL(_array_java_lang_String__V));
if (mb == NULL || !(mb->access_flags & ACC_STATIC)) {
signalException(java_lang_NoSuchMethodError, "main");
goto error;
}
/* Create the String array holding the command line args */
i = class_arg + 1;
if ((array_class = findArrayClass(SYMBOL(array_java_lang_String))) &&
(array = allocArray(array_class, argc - i, sizeof(Object *)))) {
Object **args = ARRAY_DATA(array, Object*) - i;
for (; i < argc; i++)
if (!(args[i] = Cstr2String(argv[i])))
break;
/* Call the main method */
if (i == argc)
executeStaticMethod(main_class, mb, array);
}
error:
/* ExceptionOccurred returns the exception or NULL, which is OK
for normal conditionals, but not here... */
if ((status = exceptionOccurred() ? 1 : 0))
uncaughtException();
/* Wait for all but daemon threads to die */
mainThreadWaitToExitVM();
// TODO 关闭虚拟机
exitVM(status);
/* Keep the compiler happy */
return 0;
}
上面简单地进行了注释,我们根据这个流程做分析,首先这一篇分析解析参数。
// 解析命令参数
class_arg = parseCommandLine(argc, argv, &args);
这里传入的参数有三个,前两个是main函数的参数,代表了命令行的参数个数和参数数组,第三个是运行的初始化参数
typedef struct InitArgs {
int asyncgc;
int verbosegc;
int verbosedll;
int verboseclass;
int compact_specified; /* Whether compaction has been given on the
command line, and the value if it has */
int do_compact;
int trace_jni_sigs;
char *classpath; //classpath字面意思
char *bootpath;
char *bootpath_a;
char *bootpath_p;
char *bootpath_c;
char *bootpath_v;
int java_stack;
unsigned long min_heap; // 最小堆栈值
unsigned long max_heap; // 最大堆栈值
Property *commandline_props;
int props_count;
void *main_stack_base; // 运行的类栈
/* JNI invocation API hooks */
int (*vfprintf)(FILE *stream, const char *fmt, va_list ap);
void (*exit)(int status);
void (*abort)(void);
#ifdef INLINING
unsigned int codemem;
int replication_threshold;
int profile_threshold;
int branch_patching_dup;
int branch_patching;
int print_codestats;
int join_blocks;
int profiling;
#endif
#ifdef HAVE_PROFILE_STUBS
int dump_stubs_profiles;
#endif
} InitArgs;
这个是这个初始化参数的结构体,注释了解析命令行参数需要用的参数的含义