CVM虛擬機的啓動過程

位於Java_md.c中的main() 函數調用與ANSI兼容的ansiJavaMain() 函數來實現自舉。ansiJavaMain()做的第一件事情是轉換和處理虛擬機的命令行參數,然後調用定義在JNI Invocation API中定義的JNI_CreateJavaVM() 函數來創建和初始化CVM。在這個工程當中,它初始化所有的VM全局狀態變量(VM global states,位於global.c中的全局變量CVMGlobalState CVMglobals當中),包括system mutexes, Java heap, threads, classloaders 等等。在虛擬機成功創建之後,它載入Java應用的main class並調用main Java方法。最先調用sun.misc.CVM類中的runMain()方法,該方法根據Java應用的主類名反射生成class,然後在調用該class中定義的main()方法。

所有的初始化工作都在JNI_CreateJavaVM(JavaVM **p_jvm, void **p_env, void *args)函數中進行,該函數調用CVMinitVMGlobalState(),initializeSystemClasses()等衆多初始化函數。

 

1          Preloader Initialization

CVMpreloaderInit()

CVM支持class ROMization(在編譯的時候), 有時我們也稱它爲class preloadingVM一開始需要做的少數幾件事之一就是初始化ROMized classes。對於每一個ROMized class blocks (CVMClassBlock 是存儲Java類元數據的主要數據結構),虛擬機找到它們(class blocks)相應的Java實例並通過填充它們的class block pointer, classloader point等對它們進行初始化。虛擬機也對被壓縮的字符串數據進行迭代並通過填充字符串valueoffset和長度等來構造匹配的Java實例。注意: 這些ROMized classes並不存活在Java heap當中。

CVM中,method的數據結構(CVMMethdBlock)由不可變和可變部分組成。不可變部分包括方面和type ID,方法表索引(methodtable index)等。一旦被JCC(ROMizer)classloader初始化後,這些域將絕不會被修改。可變部分包括調用者(invoker pointer)指針,編譯後代碼的起始PC(compiled code start PC)等。作爲preloader初始化的一部分,VM通過拷貝不變部分和填充可變部分來爲每個ROMized的類初始化method data

 

 

2          System Mutexes Initialization

可能在CVMinitVMGlobalState()函數進行初始化

CVM有用遍及整個VM子系統的控制銅鼓的全局mutexes。這包括jit lock, heap lock, thread-list lock, class table lock, loader cache lock, global roots lock, weak global roots lock, typeid lock等。在自舉工程當中,CVM創建並初始化這些全局locks

 

 

3          初始化GC Global Root Stacks

調用CVMinitGCRootStack()函數對各個stack進行初始化。初始化GC root stacks包括global roots stack (for allocating JNI global references and CVM global roots), weak global roots stack (for allocating JNI weak global references), class global roots stack, classloader global roots stack, protection domain global roots stack, and class table root stack(for all dynamically loaded classes). The global root stacks are used by GC for scanning live objects.

 

 

4          Typeid System Initialization

CVMinitVMGlobalState() -> CVMtypeidInit()

VM做的下一件事情就是初始化typeid system並註冊一些常用typeids,例如: CVMglobals中的<init>, <clinit>, finalize 等。這可以避免在運行時重複的搜索這些typeid

 

5          Classes System Initialization

CVMinitVMGlobalState() -> CVMclassModuleInit()

CVMglobals.loaderCache = (CVMLoaderCacheEntry **)

       calloc(CVM_LOADER_CACHE_TABLE_SIZE, sizeof(CVMLoaderCacheEntry*));

the class loader cache 初始化,載入器緩衝區用來緩存所有系統所載入的<Class, ClassLoader>對。載入器保存了一個"(classID, loader) => cb"的映射。Cache中的所有類已經檢驗過滿足class loader constraintsCache加快了類載入。

注意: "(classID, loader) => cb"影射中,"loader"initiating loader, 沒有必要是最終定義(define)classloader。一個類載入器可以將類載入委派到另一個類載入器。

例如: "java/lang/Stringan applet class loader載入時,實際上產生的classNULL作爲它的類載入器。然而,一個載入的類也將總get an entry with its actual class loader.

當一個新的類將被添加到cache當中的時候,必須確保它不會破壞任何已經存在的約束(constraints)

在執行過程當中,作爲class連接的結果,可能會增加新的約束。在增加每一個新的約束前,必須確保cache中緩存的classes將滿足新的約束。

 

 

6          初始化Java(Heap)

CVM使用-Xms, -Xmn –Xmx 選項來制定起始、最小和最大的堆尺寸。它從VM參數中提取這些尺寸信息,並分配一個起始大小的堆。在運行的時候,heap能夠增長到最大尺寸。

CVMinitVMGlobalState -> CVMgcInitHeap(CVMOptions *options) -> CVMgcimplInitHeap -> CVMmemMap -> mmap

 

 

7          Preallocating Object Monitors and Exception Objects

初始化Monitor: CVMBool CVMeeSyncInitGlobal(CVMExecEnv *ee, CVMGlobalState *gs)

初始化異常對象: CVMinitVMGlobalState -> CVMID_allocNewInstance(ee, CVMsystemClass(java_lang_OutOfMemoryError),

 

VM創建一定初始數目的object monitors。這是虛擬機所知的、它所需要的最小數目。desperation exception objects包括OutOfMemoryError, StackOverflowError等。

 

 

8          JVMTI(tool interface) 初始化

/* jvmti global variables initialization */

    CVMjvmtiInitializeGlobals(&gs->jvmti);

如果支持debugger profiler, 那麼CVM也執行JVMTI相關的初始化,TIdebugger profiler的替代品。

 

 

9          JIT初始化

  if (!CVMjitInit(ee, &gs->jit, options->jitAttributesStr))

/* Initialize the invoker cost of all ROMized methods */

    CVMpreloaderInitInvokeCost();

如果支持運行時編譯(JIT),那麼虛擬機需要執行JIT相關的初始化,包括初始化編譯策略,後端編譯器,代碼緩存區等。

 

 

10     初始化一些系統類: initializeSystemClasses

JNI_CreateJavaVM  ->  static char* initializeSystemClasses

CVM_LVM 默認爲false

ROMized的系統類需要明確地被VM進行初始化。首先,它首先通過執行它們的靜態初始化塊(static initializers) 來初始化那些不需要線程支持的系統類。這包括java.lang.Class, java.lang.String, java.lang.Shutdown, java.lang.ClassLoader等等。

然後它創建System ThreadGroup, main ThreadGroup, and main Thread objects.在線程對象初始化後,VM調用System.initializeSystemClass()來設置system properties, stdin, stdout, and stderr。在此期間,它也創建:

A Reference handler thread, which enqueues pending References

A Finalizer thread that runs the finalizer.

 

 

// 默認一般不會啓動 LVM

static CVMBool CVMLVMinitSystemClasses(JNIEnv* env, jobject initThread)

{

systemClass = CVMcbJavaInstance(CVMsystemClass(java_lang_System));

       initMethodID = (*env)->GetStaticMethodID(env, systemClass,

                                           "initializeSystemClass",

                                           "()V");

       CVMassert(initMethodID != NULL);

       (*env)->CallStaticVoidMethod(env, systemClass, initMethodID);

 

 

11     解析剩餘的命令行參數

/* Parse the command line options that are passed in (mostly done in sun.misc.CVM) */

    errorStr = CVMparseCommandLineOptions(env, initArgs,

                                     numUnrecognizedOptions);

虛擬機調用sun.misc.CVM.parseCommandLineOptions()來解析剩餘的參數,在此過程當中,它增加用戶定義的屬性,並尋找main函數所在的類名。

現在CVM準備執行main方法, 它首先需要找到main Java class。它創建system classloader(sun.misc.Launcher$AppClassLoader),並使用這個classloader來搜索和載入main class。在這個class被成功載入後,它調用main()放吧並開始執行Java字節碼。

 

發佈了24 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章