JamVM 程序的入口点在 jam.c 的 main 函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 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)) { printf ("Could not initialise VM. Aborting.\n" ); exit (1 ); } if ((system_loader = getSystemClassLoader()) == NULL ) goto error; mainThreadSetContextClassLoader(system_loader); for (cpntr = argv[class_arg]; *cpntr; cpntr++) if (*cpntr == '.' ) *cpntr = '/' ; main_class = findClassFromClassLoader(argv[class_arg], system_loader); if (main_class != NULL ) initClass(main_class); if (exceptionOccurred()) goto error; 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; } 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 ; if (i == argc) executeStaticMethod(main_class, mb, array ); } error: if ((status = exceptionOccurred() ? 1 : 0 )) uncaughtException(); mainThreadWaitToExitVM(); exitVM(status); return 0 ; }
JavaVM 各个模块的初始化 在 main 中调用 initVM 进行各个模块的初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 int initVM (InitArgs *args) { int status; initialisePlatform(); status = initialiseHooks(args) && initialiseProperties(args) && initialiseAlloc(args) && initialiseThreadStage1(args) && initialiseUtf8() && initialiseSymbol() && initialiseClassStage1(args) && initialiseDll(args) && initialiseMonitor() && initialiseString() && initialiseException() && initialiseNatives() && initialiseAccess() && initialiseFrame() && initialiseJNI() && initialiseInterpreter(args) && initialiseClassStage2() && initialiseThreadStage2(args) && initialiseGC(args); VM_initing = FALSE; return status; }
initialiseHooks 初始化定义在 hooks.c 中的全局变量 vfprintf_hook 和 exit_hook,导出两个函数 jam_fprintf
和 jamvm_exit
其中模块就可以使用上面的两个函数,进行控制台打印输出。
1 2 3 4 5 6 7 8 9 10 int initialiseHooks (InitArgs *args) { vfprintf_hook = args->vfprintf ; exit_hook = args->exit ; return TRUE; }
initialiseProperties 初始化三个变量
1 2 3 4 5 6 7 8 9 static Property *commandline_props;static int commandline_props_count;static char *java_home;
initialiseAlloc 初始化堆区(heap)
其中使用到了三个参数:
args->min_heap
这个参数可以通过 -Xms 进行设置
set the initial size of the heap (default = MAX(physical memory/64, 16M))
其含义是设置堆的初始化分配的内存。
args->max_heap
这个参数可以通过 -Xmx 进行设置
set the maximum size of the heap (default = MIN(physical memory/4, 256M))
表示 JamVM 堆的最大内存
args->verbosegc
Set verbose option from initialisation arguments
当这个选项是 TRUE 的时候,gc 线程在进行 gc 的时候会输出详细信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 (n+m-1 )&~(m-1 ) rn = (n)&~(m-1 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 int initialiseAlloc (InitArgs *args) { char *mem = (char *)mmap(0 , args->max_heap, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1 , 0 ); if (mem == MAP_FAILED) { perror("Couldn't allocate the heap; try reducing the max " "heap size (-Xmx)" ); return FALSE; } heapbase = (char *)(((uintptr_t )mem+HEADER_SIZE+OBJECT_GRAIN-1 )& ~(OBJECT_GRAIN-1 ))-HEADER_SIZE; heaplimit = heapbase+((args->min_heap-(heapbase-mem))&~(OBJECT_GRAIN-1 )); heapmax = heapbase+((args->max_heap-(heapbase-mem))&~(OBJECT_GRAIN-1 )); freelist = (Chunk*)heapbase; freelist->header = heapfree = heaplimit-heapbase; freelist->next = NULL ; TRACE_GC("Alloced heap size %p\n" , heaplimit-heapbase); allocMarkBits(); initVMLock(heap_lock); initVMLock(has_fnlzr_lock); initVMLock(registered_refs_lock); initVMWaitLock(run_finaliser_lock); initVMWaitLock(reference_lock); sys_page_size = getpagesize(); verbosegc = args->verbosegc; return TRUE; }
initialiseThreadStage1 初始化线程相关的锁。
初始化 当前线程(主线程)的 Thread 对象 main_thread, 使用 pthread_setspecific 放到当前线程的 TLS 中。
initialiseUtf8 初始化一个 HashTable 对象。
1 2 static HashTable hash_table;
initialiseSymbol 初始化 JVM 所使用的符号
initialiseClassStage1 初始化 bootpath, 从参数中获取,从默认的配置中获取。
将 bootpath 转化成 static BCPEntry *bootclasspath;
initialiseDll 初始化动态链接库的路径。
initialiseMonitor initialiseString 1 2 3 4 5 6 7 static Class *string_class;static int value_offset;static HashTable hash_table;
initialiseException 初始化异常相关的类
initialiseNatives initialiseAccess initialiseFrame initialiseJNI 初始化 JNI 相关的锁
initialiseInterpreter 初始化解释器相关的锁
initialiseClassStage2 初始化 java_lang_Class 类,
initialiseThreadStage2 初始化 java_lang_Thread 类,缓存一些重要的字段偏移量。
并创建一个 Signal Handler 线程。
initialiseGC
在堆上预先分配一个 java_lang_OutOfMemoryError 对象
创建一个 Finalizer 线程
创建一个 Reference Handler 线程
JamVM 的初始化,就是初始化各个模块的全局变量,锁,分配需要的内存,启动相关的线程。
$. 参考
mmap
地址对齐的位运算代码的解释
Data structure alignment
static关键字的用法
Internal Linkage
offsetof Macro