JVM源码分析-Java运行
生活随笔
收集整理的這篇文章主要介紹了
JVM源码分析-Java运行
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
這個實現使用的是C代碼(位于share/tools/launcher中的java.c),關注一下是如何執行這個命令的。?
過程主要就是按照參數加載虛擬機,然后找到指定類,執行其main方法。
整個C程序是從main函數開始:
1?int
2?main(int?argc,?char?**?argv)
3?{
4?????char?*jarfile?=?0;
5?????char?*classname?=?0;
6?????char?*s?=?0;
7?????char?*main_class?=?NULL;
8?????int?ret; 設置運行時環境:
CreateExecutionEnvironment(&argc,?&argv,
???????????????????????????????jrepath,?sizeof(jrepath),
???????????????????????????????jvmpath,?sizeof(jvmpath),
???????????????????????????????original_argv); 加載JVM:
1???if?(!LoadJavaVM(jvmpath,?&ifn))?{
2???????exit(6);
3?????} 設置Classpath:
SetClassPath 設置各種參數
1???/*?set?the?-Dsun.java.command?pseudo?property?*/
2?????SetJavaCommandLineProp(classname,?jarfile,?argc,?argv);
3?
4?????/*?Set?the?-Dsun.java.launcher?pseudo?property?*/
5?????SetJavaLauncherProp();
6?
7?????/*?set?the?-Dsun.java.launcher.*?platform?properties?*/
8?????SetJavaLauncherPlatformProps();
設置線程棧大小:
1???if?(threadStackSize?==?0)?{
2???????struct?JDK1_1InitArgs?args1_1;
3???????memset((void*)&args1_1,?0,?sizeof(args1_1));
4???????args1_1.version?=?JNI_VERSION_1_1;
5???????ifn.GetDefaultJavaVMInitArgs(&args1_1);??/*?ignore?return?value?*/
6???????if?(args1_1.javaStackSize?>?0)?{
7??????????threadStackSize?=?args1_1.javaStackSize;
8???????}
9?????}
創建一個新的線程創建JVM并調用main方法。
?1??{?/*?Create?a?new?thread?to?create?JVM?and?invoke?main?method?*/
?2???????struct?JavaMainArgs?args;
?3?
?4???????args.argc?=?argc;
?5???????args.argv?=?argv;
?6???????args.jarfile?=?jarfile;
?7???????args.classname?=?classname;
?8???????args.ifn?=?ifn;
?9?
10???????return?ContinueInNewThread(JavaMain,?threadStackSize,?(void*)&args);
11?????} 最后在這個線程里調用了JavaMain,接下來是JavaMain的代碼:
1?int?JNICALL
2?JavaMain(void?*?_args)
3?{
4?????struct?JavaMainArgs?*args?=?(struct?JavaMainArgs?*)_args;
5?????int?argc?=?args->argc;
6?????char?**argv?=?args->argv;
7?????char?*jarfile?=?args->jarfile;
8?????char?*classname?=?args->classname; 下面就是調用Java里的main方法了,當然首先是加載類:
1?if?(jarfile?!=?0)?{
2?????????mainClassName?=?GetMainClassName(env,?jarfile); 根據class的名字加載class:
1??classname?=?(char?*)(*env)->GetStringUTFChars(env,?mainClassName,?0);
2?????????if?(classname?==?NULL)?{
3?????????????ReportExceptionDescription(env);
4?????????????goto?leave;
5?????????}
6?????????mainClass?=?LoadClass(env,?classname); 還有其他情況:
?1???mainClassName?=?NewPlatformString(env,?classname);
?2???????if?(mainClassName?==?NULL)?{
?3?????????const?char?*?format?=?"Failed?to?load?Main?Class:?%s";
?4?????????message?=?(char?*)JLI_MemAlloc((strlen(format)?+?strlen(classname))?*
?5????????????????????????????????????sizeof(char)?);
?6?????????sprintf(message,?format,?classname);
?7?????????messageDest?=?JNI_TRUE;
?8?????????goto?leave;
?9???????}
10???????classname?=?(char?*)(*env)->GetStringUTFChars(env,?mainClassName,?0);
11???????if?(classname?==?NULL)?{
12?????????ReportExceptionDescription(env);
13?????????goto?leave;
14???????}
15???????mainClass?=?LoadClass(env,?classname); 接下來就是調用java中的main方法了,這是一個靜態方法:
1???/*?Get?the?application's?main?method?*/
2?????mainID?=?(*env)->GetStaticMethodID(env,?mainClass,?"main",
3????????????????????????????????????????"([Ljava/lang/String;)V");
確認main方法是public的
?1??{????/*?Make?sure?the?main?method?is?public?*/
?2?????????jint?mods;
?3?????????jmethodID?mid;
?4?????????jobject?obj?=?(*env)->ToReflectedMethod(env,?mainClass,
?5?????????????????????????????????????????????????mainID,?JNI_TRUE);
?6?
?7?????????if(?obj?==?NULL)?{?/*?exception?occurred?*/
?8?????????????ReportExceptionDescription(env);
?9?????????????goto?leave;
10?????????}
11?
12?????????mid?=
13???????????(*env)->GetMethodID(env,
14???????????????????????????????(*env)->GetObjectClass(env,?obj),
15???????????????????????????????"getModifiers",?"()I");
1??mods?=?(*env)->CallIntMethod(env,?obj,?mid);
2?????????if?((mods?&?1)?==?0)?{?/*?if?(!Modifier.isPublic(mods))??*/
3?????????????message?=?"Main?method?not?public.";
4?????????????messageDest?=?JNI_TRUE;
5?????????????goto?leave;
6?????????}
構建參數:
1????/*?Build?argument?array?*/
2?????mainArgs?=?NewPlatformStringArray(env,?argv,?argc);
3?????if?(mainArgs?==?NULL)?{
4?????????ReportExceptionDescription(env);
5?????????goto?leave;
6?????} 調用main方法:
1??/*?Invoke?main?method.?*/
2?????(*env)->CallStaticVoidMethod(env,?mainClass,?mainID,?mainArgs); 脫離線程:
?1???/*
?2??????*?Detach?the?main?thread?so?that?it?appears?to?have?ended?when
?3??????*?the?application's?main?method?exits.??This?will?invoke?the
?4??????*?uncaught?exception?handler?machinery?if?main?threw?an
?5??????*?exception.??An?uncaught?exception?handler?cannot?change?the
?6??????*?launcher's?return?code?except?by?calling?System.exit.
?7??????*/
?8?????if?((*vm)->DetachCurrentThread(vm)?!=?0)?{
?9?????????message?=?"Could?not?detach?main?thread.";
10?????????messageDest?=?JNI_TRUE;
11?????????ret?=?1;
12?????????goto?leave;
13?????}
銷毀虛擬機,得等所有線程都結束,因為虛擬機是一個守護線程:
?1?leave:
?2?????/*
?3??????*?Wait?for?all?non-daemon?threads?to?end,?then?destroy?the?VM.
?4??????*?This?will?actually?create?a?trivial?new?Java?waiter?thread
?5??????*?named?"DestroyJavaVM",?but?this?will?be?seen?as?a?different
?6??????*?thread?from?the?one?that?executed?main,?even?though?they?are
?7??????*?the?same?C?thread.??This?allows?mainThread.join()?and
?8??????*?mainThread.isAlive()?to?work?as?expected.
?9??????*/
10?????(*vm)->DestroyJavaVM(vm);
回過頭來比較重要的幾個方法:
1 LoadClass
2 GetStaticMethodID
3 GetMethodID
4 CallIntMethod
5 CallStaticVoidMethod
6 ContinueInNewThread
7 LoadJavaVM
這些方法基本上就是我們平常寫代碼比較關注的了。
LoadClass
?1?/*?2??*?Loads?a?class,?convert?the?'.'?to?'/'.
?3??*/
?4?static?jclass
?5?LoadClass(JNIEnv?*env,?char?*name)
?6?{
?7?????char?*buf?=?JLI_MemAlloc(strlen(name)?+?1);
?8?????char?*s?=?buf,?*t?=?name,?c;
?9?????jclass?cls;
10?????jlong?start,?end;
11?
12?????if?(_launcher_debug)
13?????????start?=?CounterGet();
14?
15?????do?{
16?????????c?=?*t++;
17?????????*s++?=?(c?==?'.')???'/'?:?c;
18?????}?while?(c?!=?'\0');
19?????cls?=?(*env)->FindClass(env,?buf);
20?????JLI_MemFree(buf);
21?
22?????if?(_launcher_debug)?{
23?????????end???=?CounterGet();
24?????????printf("%ld?micro?seconds?to?load?main?class\n",
25????????????????(long)(jint)Counter2Micros(end-start));
26?????????printf("----_JAVA_LAUNCHER_DEBUG----\n");
27?????}
28?
29?????return?cls;
30?}
其中有個主要方法是調用JNIEnv的FindClass方法去找class:
在下載的源代碼中jni.h位于share/vm/prims,在網上找到如下代碼:
http://home.pacifier.com/~mmead/jni/cs510ajp/jni.h?
??1?/* ?2??*?We?use?inlined?functions?for?C++?so?that?programmers?can?write:
?3??*?
?4??*????env->FindClass("java/lang/String")
?5??*
?6??*?in?C++?rather?than:
?7??*
?8??*????(*env)->FindClass(env,?"java/lang/String")
?9??*
10??*?in?C.
11??*/
12?
13?struct?JNIEnv_?{
14?????const?struct?JNINativeInterface_?*functions;
15?????void?*reserved0;
16?????void?*reserved1[6];
17?#ifdef?__cplusplus
18?
19?????jint?GetVersion()?{
20?????????return?functions->GetVersion(this);
21?????}
22?????jclass?DefineClass(const?char?*name,?jobject?loader,?const?jbyte?*buf,
23????????????????jsize?len)?{
24?????????return?functions->DefineClass(this,?name,?loader,?buf,?len);
25?????}
26?????jclass?FindClass(const?char?*name)?{
27?????????return?functions->FindClass(this,?name);
28?????}
?JNI是依賴于Java Runtime Interface的:
/*?
?*?We?used?part?of?Netscape's?Java?Runtime?Interface?(JRI)?as?the?starting
?*?point?of?our?design?and?implementation.
?*/ 具體可以看這里和這里。
注意JNINativeInterface_ 這個結構體,實際上之前說的那些方法,最終都是調用了它: ?jclass?(JNICALL?*FindClass)??(JNIEnv?*env,?const?char?*name); jmethodID?(JNICALL?*GetStaticMethodID)???????(JNIEnv?*env,?jclass?clazz,?const?char?*name,?const?char?*sig);
?void?(JNICALL?*CallStaticVoidMethod)
??????(JNIEnv?*env,?jclass?cls,?jmethodID?methodID,?); 這種寫法在C++里叫inline function,調用方法就是像上面寫的那樣:
?1?/*
?2??*?We?use?inlined?functions?for?C++?so?that?programmers?can?write:
?3??*?
?4??*????env->FindClass("java/lang/String")
?5??*
?6??*?in?C++?rather?than:
?7??*
?8??*????(*env)->FindClass(env,?"java/lang/String")
?9??*
10??*?in?C.
11??*/ share/vm/prims中包含了jni的大量實現代碼,對于上面的概述進行了細化,如果想知道怎么加載例如FindClass這樣的方法,以及它們內部到底干了什么,就得看這部分了。
?
LoadJavaVM
LoadJavaVM和DestroyJavaVM等跟VM有關的方法,都與share/vm/prims中的jvm.h,jvm.cpp有關。
這個方法解釋如下:
?1?/*
?2??*?This?file?contains?additional?functions?exported?from?the?VM.
?3??*?These?functions?are?complementary?to?the?standard?JNI?support.
?4??*?There?are?three?parts?to?this?file:
?5??*
?6??*?First,?this?file?contains?the?VM-related?functions?needed?by?native
?7??*?libraries?in?the?standard?Java?API.?For?example,?the?java.lang.Object
?8??*?class?needs?VM-level?functions?that?wait?for?and?notify?monitors.
?9??*
10??*?Second,?this?file?contains?the?functions?and?constant?definitions
11??*?needed?by?the?byte?code?verifier?and?class?file?format?checker.
12??*?These?functions?allow?the?verifier?and?format?checker?to?be?written
13??*?in?a?VM-independent?way.
14??*
15??*?Third,?this?file?contains?various?I/O?and?nerwork?operations?needed
16??*?by?the?standard?Java?I/O?and?network?APIs.
17??*/
18?
19?/*
20??*?Bump?the?version?number?when?either?of?the?following?happens:
21??*
22??*?1.?There?is?a?change?in?JVM_*?functions.
23??*
24??*?2.?There?is?a?change?in?the?contract?between?VM?and?Java?classes.
25??*????For?example,?if?the?VM?relies?on?a?new?private?field?in?Thread
26??*????class.
27??*/
這里面包括了VM這個層次上的抽象,大到創建Java線程,加載類,解析字節碼,小到JVM原生支持的Java方法。
下面是從bootstrap class loader的代碼,Java的根class loader是c++實現的。
?1?//?Returns?a?class?loaded?by?the?bootstrap?class?loader;?or?null
?2?//?if?not?found.??ClassNotFoundException?is?not?thrown.
?3?//
?4?//?Rationale?behind?JVM_FindClassFromBootLoader
?5?//?a>?JVM_FindClassFromClassLoader?was?never?exported?in?the?export?tables.
?6?//?b>?because?of?(a)?java.dll?has?a?direct?dependecy?on?the??unexported
?7?//????private?symbol?"_JVM_FindClassFromClassLoader@20".
?8?//?c>?the?launcher?cannot?use?the?private?symbol?as?it?dynamically?opens
?9?//????the?entry?point,?so?if?something?changes,?the?launcher?will?fail
10?//????unexpectedly?at?runtime,?it?is?safest?for?the?launcher?to?dlopen?a
11?//????stable?exported?interface.
12?//?d>?re-exporting?JVM_FindClassFromClassLoader?as?public,?will?cause?its
13?//????signature?to?change?from?_JVM_FindClassFromClassLoader@20?to
14?//????JVM_FindClassFromClassLoader?and?will?not?be?backward?compatible
15?//????with?older?JDKs.
16?//?Thus?a?public/stable?exported?entry?point?is?the?right?solution,
17?//?public?here?means?public?in?linker?semantics,?and?is?exported?only
18?//?to?the?JDK,?and?is?not?intended?to?be?a?public?API.
19?
20?JVM_ENTRY(jclass,?JVM_FindClassFromBootLoader(JNIEnv*?env,
21???????????????????????????????????????????????const?char*?name))
22???JVMWrapper2("JVM_FindClassFromBootLoader?%s",?name);
為了對這個重要的文件有個整體認識,下面再摘錄幾段:
/*************************************************************************
?PART?1:?Functions?for?Native?Libraries
?************************************************************************/
/*
?*?java.lang.Object
?*/
JNIEXPORT?jint?JNICALL
JVM_IHashCode(JNIEnv?*env,?jobject?obj);
JNIEXPORT?void?JNICALL
JVM_MonitorWait(JNIEnv?*env,?jobject?obj,?jlong?ms);
JNIEXPORT?void?JNICALL
JVM_MonitorNotify(JNIEnv?*env,?jobject?obj);
JNIEXPORT?void?JNICALL
JVM_MonitorNotifyAll(JNIEnv?*env,?jobject?obj);
JNIEXPORT?jobject?JNICALL
JVM_Clone(JNIEnv?*env,?jobject?obj); 可以看到對象上有個監視器來執行線程的Wait和Notify。
PartI中跟線程有關的:
?1?/*
?2??*?java.lang.Thread
?3??*/
?4?JNIEXPORT?void?JNICALL
?5?JVM_StartThread(JNIEnv?*env,?jobject?thread);
?6?
?7?JNIEXPORT?void?JNICALL
?8?JVM_StopThread(JNIEnv?*env,?jobject?thread,?jobject?exception);
?9?
10?JNIEXPORT?jboolean?JNICALL
11?JVM_IsThreadAlive(JNIEnv?*env,?jobject?thread);
12?
13?JNIEXPORT?void?JNICALL
14?JVM_SuspendThread(JNIEnv?*env,?jobject?thread);
15?
16?JNIEXPORT?void?JNICALL
17?JVM_ResumeThread(JNIEnv?*env,?jobject?thread);
18?
19?JNIEXPORT?void?JNICALL
20?JVM_SetThreadPriority(JNIEnv?*env,?jobject?thread,?jint?prio);
21?
22?JNIEXPORT?void?JNICALL
23?JVM_Yield(JNIEnv?*env,?jclass?threadClass);
24?
25?JNIEXPORT?void?JNICALL
26?JVM_Sleep(JNIEnv?*env,?jclass?threadClass,?jlong?millis);
27?
28?JNIEXPORT?jobject?JNICALL
29?JVM_CurrentThread(JNIEnv?*env,?jclass?threadClass);
30?
31?JNIEXPORT?jint?JNICALL
32?JVM_CountStackFrames(JNIEnv?*env,?jobject?thread);
33?
34?JNIEXPORT?void?JNICALL
35?JVM_Interrupt(JNIEnv?*env,?jobject?thread);
36?
37?JNIEXPORT?jboolean?JNICALL
38?JVM_IsInterrupted(JNIEnv?*env,?jobject?thread,?jboolean?clearInterrupted);
39?
40?JNIEXPORT?jboolean?JNICALL
41?JVM_HoldsLock(JNIEnv?*env,?jclass?threadClass,?jobject?obj);
42?
43?JNIEXPORT?void?JNICALL
44?JVM_DumpAllStacks(JNIEnv?*env,?jclass?unused);
45?
46?JNIEXPORT?jobjectArray?JNICALL
47?JVM_GetAllThreads(JNIEnv?*env,?jclass?dummy); 第二部分主要是驗證class格式
?1?/*************************************************************************
?2??PART?2:?Support?for?the?Verifier?and?Class?File?Format?Checker
?3??************************************************************************/
?4?/*
?5??*?Return?the?class?name?in?UTF?format.?The?result?is?valid
?6??*?until?JVM_ReleaseUTf?is?called.
?7??*
?8??*?The?caller?must?treat?the?string?as?a?constant?and?not?modify?it
?9??*?in?any?way.
10??*/
11?JNIEXPORT?const?char?*?JNICALL
12?JVM_GetClassNameUTF(JNIEnv?*env,?jclass?cb);
13?
14?/*
15??*?Returns?the?constant?pool?types?in?the?buffer?provided?by?"types."
16??*/
17?JNIEXPORT?void?JNICALL
18?JVM_GetClassCPTypes(JNIEnv?*env,?jclass?cb,?unsigned?char?*types);
19?
20?/*
21??*?Returns?the?number?of?Constant?Pool?entries.
22??*/
23?JNIEXPORT?jint?JNICALL
24?JVM_GetClassCPEntriesCount(JNIEnv?*env,?jclass?cb);
25?
26?/*
27??*?Returns?the?number?of?*declared*?fields?or?methods.
28??*/
29?JNIEXPORT?jint?JNICALL
30?JVM_GetClassFieldsCount(JNIEnv?*env,?jclass?cb);
第三部分主要是對IO和網絡的支持,包括了File和Socket
?1?/*************************************************************************
?2??PART?3:?I/O?and?Network?Support
?3??************************************************************************/
?4?
?5?/*?Note?that?the?JVM?IO?functions?are?expected?to?return?JVM_IO_ERR
?6??*?when?there?is?any?kind?of?error.?The?caller?can?then?use?the
?7??*?platform?specific?support?(e.g.,?errno)?to?get?the?detailed
?8??*?error?info.??The?JVM_GetLastErrorString?procedure?may?also?be?used
?9??*?to?obtain?a?descriptive?error?string.
10??*/
11?#define?JVM_IO_ERR??(-1)
12?
13?/*?For?interruptible?IO.?Returning?JVM_IO_INTR?indicates?that?an?IO
14??*?operation?has?been?disrupted?by?Thread.interrupt.?There?are?a
15??*?number?of?technical?difficulties?related?to?interruptible?IO?that
16??*?need?to?be?solved.?For?example,?most?existing?programs?do?not?handle
17??*?InterruptedIOExceptions?specially,?they?simply?treat?those?as?any
18??*?IOExceptions,?which?typically?indicate?fatal?errors.
19??*
20??*?There?are?also?two?modes?of?operation?for?interruptible?IO.?In?the
21??*?resumption?mode,?an?interrupted?IO?operation?is?guaranteed?not?to
22??*?have?any?side-effects,?and?can?be?restarted.?In?the?termination?mode,
23??*?an?interrupted?IO?operation?corrupts?the?underlying?IO?stream,?so
24??*?that?the?only?reasonable?operation?on?an?interrupted?stream?is?to
25??*?close?that?stream.?The?resumption?mode?seems?to?be?impossible?to
26??*?implement?on?Win32?and?Solaris.?Implementing?the?termination?mode?is
27??*?easier,?but?it's?not?clear?that's?the?right?semantics.
28??*
29??*?Interruptible?IO?is?not?supported?on?Win32.It?can?be?enabled/disabled
30??*?using?a?compile-time?flag?on?Solaris.?Third-party?JVM?ports?do?not
31??*?need?to?implement?interruptible?IO.
32??*/
33?#define?JVM_IO_INTR?(-2)
有個結論是:整個Hotspot JVM是以JRI為起點進行設計的基于JNI的框架,可以算是一個插件架構,通過JNI的機制擴展JVM自身。
另外在share/vm/prims中還能看到大量的jvmti開頭的文件,那么jvmti是什么東東呢?那么看這里:
??The JVMTM?Tool Interface (JVM?TI) is a new native programming interface for use by tools. It provides both a way to inspect the state and to control the execution of applications running in the Java virtual machine (JVM). JVM?TI supports the full breadth of tools that need access to JVM state, including but not limited to: profiling, debugging, monitoring, thread analysis, and coverage analysis tools.
Note: JVM?TI replaces the Java Virtual Machine Profiler Interface (JVMPI) and the Java Virtual Machine Debug Interface (JVMDI). JVMPI and JVMDI will be removed in the next major release of J2SETM.
先寫到這吧,下面一篇應該會從整個的JVM架構來講一下,然后再去對照Inside JVM和JVM規范去理解重點代碼,看其是如何實現的。我關注的重點是OO,IO,多線程以及GC,JIT這幾個方面的實現。另外一部分重點是更基礎的,JVM真正在執行層面上如何運行Java字節碼的,那些堆,棧,棧幀,PC如何創建,如何執行指令。
給自己做一個規劃吧,列個提綱:
1 JVM總體架構
2 JVM內存模型以及運行時
3 多線程
4 GC
5 OO
6 IO
7 JIT
總結
以上是生活随笔為你收集整理的JVM源码分析-Java运行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java源码分析之ArrayList
- 下一篇: 源代码阅读技巧