原文URL:http://weblogs.java.net/blog/jiangli_zhou/archive/2007/04/cvm_bootstrap.html
你可能已经知道CVM是用C写的了。因此,VM启动后发生了什么?在你的main()函数中执行的第一行java代码是什么?这在启动期间是一个连续的过程,我们通常叫这个为启动过程(bootstrap)。这篇文章将解释CVM启动过程和初始化过程的详细情况。
CVM启动代码是ansiJavaMain()(ANSI适应),它被C的main()函数调用。ansiJavaMain()做的第一件事转换和预处理VM的参数。因此,它调用JIN_CreateJavaVM()(定义在JNI Invocation API)来创建和初始化CVM。在整个过程中,它初始化所有的VM全局状态,包括系统互斥量(system mutexes),java heap,threads,classloaders,等等。在VM创建成功后,它装载java程序的主类并调用java的main()方法。
预装载初始化
CVM支持在编译期间类的容量控制(ROMization)。它通过VM装载和连接类数据。我们有时候叫它类的预装载。这些事情中,首先需要做的是初始化容量类(ROMized class)。每一个容量类块(CVMClassBlock是关于存储java class的远数据中的主要的数据结构),它发现相应的java实例并初始化它们通过填入它们类的块指针,类装载器指针等等。它重申压缩的字符串数据和结构来匹配java实例通过填入字符串值,偏移量和长度等等。注意容量类(ROMized class)不能在java heap中生存。
在CVM中,方法数据结构(CVMMethodBlock)由可变的和不可变的部分组成。不可变部分包括方法名和类型id,方法表的索引等等。一旦被JCC(ROMizer)或类装载器初始化,它们的区域就不再可写入。可变部分包括调用者指针,编译后代码开始PC等等。作为预装载器初始化的一部分,VM初始化方法数据为每一个容量可变类通过拷贝不可变部分并填入可变部分。
系统互斥量初始化
象一篇Mar Lam的blog,一张大图片(CVM地图),CVM有全局互斥量来控制VM子系统的同步问题。这包括JIT锁定,heap锁定,线程列表锁定,类表锁定,装载器缓存锁定,全局根锁定,不牢固的全局根锁定,类型id锁定等等。在整个启动过程中,CVM创建和初始化这些全局锁定。
初始化GC全局根堆
CVM初始化GC根堆,包括全局根堆(分配JNI全局参考和CVM全局根),不牢固的全局根堆(分配JNI不牢固全局参考),类全局根堆,类装载器全局根堆,保护域全局根堆,类表根堆(所有动态装载类)。全局根堆被GC使用来扫描活动对象。
类型id系统初始化
VM做的下一个事情是初始化类型id系统和注册一些通用的类型id,比如, ,在CVMglobals中的 。为了防止在运行时重复查找这些类型id。
类系统初始化
下一步是类装载器缓存初始化。装载器缓存被用来缓存所有的
初始化java heap
CVM使用-Xms, -Xmn, -Xmx选项来规定开始时的最小和最大heap size。它通过VM参数来解决这些大小信息,分配heap的开始大小。Heap可以在运行时增加到最大。
预分配对象监视者和异常对象
VM创建一个初始数量的对象监视者。这是VM知道的需要的最小数量。异常对象包括OutOfMemoryError, StackOverflowError等等。当没有可用内存的时候根据需要创建异常对象。
JVMTI初始化
如果支持调试,CVM也做 JVMTI的相关初始化。
JIT初始化
如果支持运行时编译,CVM需要做 JIT的相关初始化,包括初始化编辑策略,编译器后端,代码缓存等等。
初始化一些系统类
一些容量可变的系统类需要被VM明确的初始化。首先,它初始化这些系统类不需要线程支持来执行这些静态的初始化。它们包括 java.lang.Class, java.lang.String, java.lang.Shutdown, java.lang.ClassLoader等等。它会创建系统ThreadGroup,主ThreadGroup,主Thread对象。在这些线程初始化后,VM调用System.initializeSystemClass()来设置系统属性,stdin,stdout,stderr。在这个过程中,它还创建了:
1、 一个参考句柄线程,它询问为决的参考
2、 一个完成器线程来运行完成器。
解析参数
VM调用sun.misc.CVM.parseCommandLineOptions()来解析其他的参数。在这个过程中,它可以添加用户定义的属性,找到主类名。
现在,CVM准备好了,为了执行main()函数,首先它需要找到java主类。为次它创建一个系统类装载器(sun.misc.Launcher$AppClassLoader)并用类装载器搜索和装载主类。当类被成功装载,它调用main()方法并开始执行java代码。