真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Main方法的執(zhí)行過程是怎樣的

今天就跟大家聊聊有關(guān)Main方法的執(zhí)行過程是怎樣的,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

10年積累的做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有漳浦免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

一個(gè)簡(jiǎn)單的Main方法

public class Mm {
        public static void main(String[] args){
            Mm mm = new Mm();
            System.out.println(mm.getClass().getClassLoader());
        }
}

javac Mm.java  
java Mm
這么的話 就進(jìn)行了一次編譯并執(zhí)行

但是如上執(zhí)行的話我們是沒辦法調(diào)試的,
因此java Mm命令不要直接執(zhí)行,用gdb模式執(zhí)行
所以我們要先編譯一版openJDK,具體編譯OpenJdk代碼過程自行百度,推薦用Windows商店的ubuntu系統(tǒng)編譯

以下是OpenJdk源碼,fork別人的

https://github.com/zscchaofan/openjdk-jdk8u
gdb -q java Mm  //gdb 設(shè)置 java 命令
set args Mm  //設(shè)置參數(shù)名 具體含義不懂百度搜的
start //啟動(dòng)調(diào)試

下邊是設(shè)置的一些斷點(diǎn) 都是一個(gè)一個(gè)試出來的 
gdb 可以直接指定文件和行數(shù)打斷點(diǎn)
詳細(xì)命令可以百度 我也是百度的就不總結(jié)了 也不常用
調(diào)試代碼如果不參考別人的教程 那就得一步步的走 走幾步
就用gdb 命令查看一下當(dāng)前代碼上下附近的幾行代碼 再對(duì)應(yīng)到源碼上去看看
像我這不懂c++語言的  只能一步步走 看到方法名意圖很明顯得地方再仔細(xì)看
3       breakpoint     keep y   0x00007fffff1e7f4a in JavaMain
                                                   at /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/bin/java.c:478
4       breakpoint     keep y   0x00007ffffc97da55 in Java_java_lang_ClassLoader_findBootstrapClass at /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/native/java/lang/ClassLoader.c:265
9       breakpoint     keep y   0x00007fffff1e9c72 in GetLauncherHelperClass
                                                   at /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/bin/java.c:1250
        breakpoint already hit 1 time
14      breakpoint     keep y   0x00007ffffc97da94 in Java_java_lang_ClassLoader_findBootstrapClass at /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/native/java/lang/ClassLoader.c:272
15      breakpoint     keep y   0x00007ffffc97d3ea in Java_java_lang_ClassLoader_defineClass1
                                                   at /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/native/java/lang/ClassLoader.c:107

/mnt/d/code/openjdk-jdk8u-master 是我存放代碼的路徑
其實(shí)是d盤code下,在ubuntu下加了/mnt

啟動(dòng)調(diào)試后gdb進(jìn)入這里會(huì)自動(dòng)停下,這就是最開始的地方
/mnt/d/code/openjdk-jdk8u-master/jdk/src/share/bin/main.c

main(int argc, char **argv)
{
    .
    .省略一部分代碼 反正也看不懂
    .
    .
    return JLI_Launch(margc, margv,
                   sizeof(const_jargs) / sizeof(char *), const_jargs,
                   sizeof(const_appclasspath) / sizeof(char *), const_appclasspath,
                   FULL_VERSION,
                   DOT_VERSION,
                   (const_progname != NULL) ? const_progname : *margv,
                   (const_launcher != NULL) ? const_launcher : *margv,
                   (const_jargs != NULL) ? JNI_TRUE : JNI_FALSE,
                   const_cpwildcard, const_javaw, const_ergo_class);
}

繼續(xù)調(diào)試之后找到
/mnt/d/code/openjdk-jdk8u-master/jdk/src/share/bin/java.c方法,如下
FindBootStrapClass這個(gè)方法里查找了jdk里的這個(gè)類sun.launcher.LauncherHelper,這個(gè)類是c++和java代碼溝通的橋梁了,LauncherHelper實(shí)例化時(shí)會(huì)實(shí)例化一個(gè)系統(tǒng)類加載器AppClassLoader

if (helperClass == NULL) {
        NULL_CHECK0(helperClass = FindBootStrapClass(env,
                "sun/launcher/LauncherHelper"));
}

之后再去尋找執(zhí)行類的Main方法并執(zhí)行,就是c++調(diào)用java方法,sun.launcher.LauncherHelper#checkAndLoadMain

NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,
                "checkAndLoadMain",
                "(ZILjava/lang/String;)Ljava/lang/Class;"));

因?yàn)槲覀兪菆?zhí)行java Mm命令,所以很明顯是從Mm類中找到main方法。
其他的比如java -jar 命令還有別的解析方法尋找Main方法

LauncherHelper.checkAndLoadMain 這個(gè)方法中會(huì)通過Class.forName()查找Mm這個(gè)類,根據(jù)雙親委派機(jī)制肯定會(huì)調(diào)用虛擬機(jī)的類加載器

    at /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/native/java/lang/ClassLoader.c:265
    cls = JVM_FindClassFromBootLoader(env, clname);
    
查看參數(shù) (gdb) p clname
$53 = 0x7fffff7bf3c0 "Mm"

虛擬機(jī)返回空

at /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/native/java/lang/ClassLoader.c:272
    if (clname != buf) {
             free(clname);
         }

         return cls;
    }
查看參數(shù) (gdb) p cls
$54 = (jclass) 0x0

所以還是回到了java代碼中的AppClassLoader類加載器中父類URLClassLoader的defineClass方法中去搜索Mm.class,找到之后再去調(diào)用虛擬機(jī)方法存儲(chǔ)當(dāng)前的類

 private native Class defineClass1(String name, byte[] b, int off, int len,
                                         ProtectionDomain pd, String source);
看到這里才算明白 
為啥自定義的類加載器加載過指定類之后,new關(guān)鍵字實(shí)例化對(duì)象時(shí)還是會(huì)用系統(tǒng)類加載器加載,
new關(guān)鍵字肯定是虛擬機(jī)執(zhí)行的 如果自己實(shí)現(xiàn)類加載器 加載的類不匯報(bào)給虛擬機(jī)
那肯定虛擬機(jī)是不認(rèn)可的

在之后虛擬機(jī)會(huì)真正調(diào)用Mm的Main方法

  /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/bin/java.c
  
  (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);

雖然Main方法中有調(diào)用
Mm mm = newMm();方法,但是再也沒有走到類加載器,因?yàn)橹耙呀?jīng)加載過了

總結(jié)

  • 1.首先main方法執(zhí)行需要一個(gè)操作來啟動(dòng),像java Mm這種命令

  • 2.這種命令首先是操作系統(tǒng)解析找到j(luò)ava命令屬于jdk的東西,并調(diào)用jdk的的啟動(dòng)函數(shù), 就像windows的雙擊操作一樣,雙擊肯定是操作系統(tǒng)搞了什么小動(dòng)作打開了軟件

  • 3.當(dāng)操作系統(tǒng)調(diào)用了虛擬機(jī)的命令后,虛擬機(jī)會(huì)拿到命令的參數(shù)比如 Mm,然后去找編譯后的文件

  • 4.虛擬機(jī)找到文件后會(huì)調(diào)用jdk中的java代碼,找到這個(gè)類sun.launcher.LauncherHelper,這個(gè)類作為一個(gè)工具類,作為橋梁鏈接了c++和java代碼

  • 5.調(diào)用sun.launcher.LauncherHelper類的checkAndLoadMain方法,通過這個(gè)方法找執(zhí)行類Mm的Main方法

  • 6.加載好之后執(zhí)行Main

有關(guān)類加載器一個(gè)問題

之前想過一個(gè)問題就是如何讓new關(guān)鍵字實(shí)例化的時(shí)候用自定義類加載器?
現(xiàn)在感覺好像無法實(shí)現(xiàn),除非替換jdk的類加載器!
//Main
public class CustomerMain {
	public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
		CustomerClassLoader customerClassLoader = new CustomerClassLoader();
		CustomerMain customerMain = (CustomerMain)(customerClassLoader.findClass("CustomerMain").newInstance());
	}
}
//自定義類加載器
class CustomerClassLoader extends ClassLoader{
	@Override
	protected Class findClass(String name) throws ClassNotFoundException {

		try {
			FileInputStream fileInputStream = new FileInputStream("D:\\code\\zerolearnspring\\target\\classes\\cn\\doourbest\\learn\\spring\\zerolearnspring\\controller\\" + name +".class");
			byte[] bb = new byte[fileInputStream.available()];
			int read = fileInputStream.read(bb);
			return defineClass("cn.doourbest.learn.spring.zerolearnspring.controller.CustomerMain",bb,0,read);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		throw new ClassNotFoundException("!!");
	}
}

-----console  錯(cuò)誤信息
Exception in thread "main" java.lang.ClassCastException: cn.doourbest.learn.spring.zerolearnspring.controller.CustomerMain cannot be cast to cn.doourbest.learn.spring.zerolearnspring.controller.CustomerMain
	at cn.doourbest.learn.spring.zerolearnspring.controller.CustomerMain.main(CustomerMain.java:18)

java虛擬機(jī)書中解釋了new對(duì)象的過程肯定會(huì)先檢查這個(gè)指令的參數(shù)能否在常量池中定位到這個(gè)類的符號(hào)引用,并且檢查這個(gè)符號(hào)引用代表的類是否已被加載、解析和初始化過,如果不存在,再去實(shí)行類加載過程。

看完上述內(nèi)容,你們對(duì)Main方法的執(zhí)行過程是怎樣的有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。


新聞標(biāo)題:Main方法的執(zhí)行過程是怎樣的
當(dāng)前鏈接:http://weahome.cn/article/jhdjjo.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部