“貓”與JVM

問題產(chǎn)生于思考Tomcat與JVM的關(guān)系械姻,發(fā)現(xiàn)自己就是個孩子,對它們一無所知。

Tomcat是一個用Java語言寫出來的應(yīng)用程序官紫,所以每運行一個Tomcat實例必將開啟一個JVM進程。啟動多個Tomcat將會產(chǎn)生多個JVM進程州藕,每個JVM進程中可以部署運行多個Web應(yīng)用程序束世,即可以存在多個類加載器(見下文)。經(jīng)過對基本概念的重新梳理床玻,簡單表示如下圖毁涉。


貓與VM.png

類加載器

  public class LookForClassLoader {
    public static void main(String[] args) {
     ClassLoader currentLoader = Thread.currentThread().getContextClassLoader();  // 獲取當(dāng)前線程上下文的類加載器
     System.out.println("current classLoader:" + currentLoader.getClass());
     System.out.println("parent classLoader:" + currentLoader.getParent().getClass());
     System.out.println("grandparent classLoader:" + currentLoader.getParent().getParent());
    }
  }

Output
current classLoader:sun.misc.Launcher$AppClassLoader@18b4aac2當(dāng)前AppClassLoader實例
parent classLoader:class sun.misc.Launcher\$ExtClassLoader@4554617c父類ExtClassLoader實例
grandparent classLoader:null祖類BootstrapClassLoader實例

祖類BootstrapClassLoader實例為null,是由C++所寫直接嵌入在 JVM 內(nèi)核中笨枯,在Java中無法獲得它的句柄薪丁,所以直接返回null。除了Java默認(rèn)提供的三個ClassLoader之外馅精,用戶可以根據(jù)需要定義自己的ClassLoader严嗜,這些自定義的ClassLoader都必須繼承自java.lang.ClassLoader類,但是Bootstrap ClassLoader不繼承自ClassLoader洲敢。當(dāng)JVM啟動后漫玄,Bootstrap ClassLoader也隨著啟動,負(fù)責(zé)加載完核心類庫后,并構(gòu)造Extension ClassLoader和App ClassLoader類加載器睦优。

類加載器關(guān)系.png

上圖展示的類加載器之間的這種層次關(guān)系渗常,稱為類加載器的雙親委派模型。雙親委派模型要求除了頂層的啟動類加載器外汗盘,其余的類加載器都應(yīng)當(dāng)有自己的父類加載器皱碘。這里類加載器之間的父子關(guān)系一般不會以繼承的關(guān)系來實現(xiàn),而是使用組合/包含關(guān)系來復(fù)用父加載器的代碼隐孽。

加載類:自頂向下
當(dāng)一個ClassLoader實例需要加載某個類時癌椿,在它親自搜索之前,會先把這個任務(wù)委托給它的父類加載器菱阵,這個過程是由上至下依次檢查的踢俄,首先由最頂層的類加載器Bootstrap ClassLoader試圖加載,如果沒加載到晴及,則把任務(wù)轉(zhuǎn)交給Extension ClassLoader試圖加載都办,如果也沒加載到,則轉(zhuǎn)交給App ClassLoader 進行加載虑稼,如果它也沒有加載得到的話琳钉,則返回給委托的發(fā)起者,由它到指定的文件系統(tǒng)或網(wǎng)絡(luò)等URL中加載該類动雹。如果它們都沒有加載到這個類時槽卫,則拋出ClassNotFoundException異常。否則將這個找到的類生成一個類的定義胰蝠,并將它加載到內(nèi)存當(dāng)中歼培,最后返回這個類在內(nèi)存中的Class實例對象。
詢問是否已加載類:自底向上
可以避免重復(fù)加載茸塞,當(dāng)父親已經(jīng)加載了該類的時候躲庄,就沒有必要子ClassLoader再加載一次。同時考慮到安全因素钾虐,我們試想一下噪窘,如果不使用這種委托模式,那我們就可以隨時使用自定義的String來動態(tài)替代java核心api中定義的類型效扫,這樣會存在非常大的安全隱患倔监,而雙親委托的方式,就可以避免這種情況菌仁,因為String已經(jīng)在啟動時就被引導(dǎo)類加載器(Bootstrcp ClassLoader)加載浩习,所以用戶自定義的ClassLoader永遠(yuǎn)也無法加載一個自己寫的String,除非改變JDK中ClassLoader搜索類的默認(rèn)算法济丘。

JVM在判定兩個class是否相同時谱秽,不僅要判斷兩個類名是否相同洽蛀,而且要判斷是否由同一個類加載器實例加載的。只有兩者同時滿足的情況下疟赊,JVM才認(rèn)為這兩個class是相同的郊供。就算兩個class是同一份class字節(jié)碼,如果被兩個不同的ClassLoader實例所加載近哟,JVM也會認(rèn)為它們是兩個不同class驮审。

BootStrap classLoader加載的類

System.out.println(System.getProperty("sun.boot.class.path")); // BootStrap classLoader加載的類

Output
D:\Java\jdk1.8.0_74\jre\lib\resources.jar;// 資源包(圖片、properties文件)
D:\Java\jdk1.8.0_74\jre\lib\rt.jar; // Bootstrap類椅挣,引導(dǎo)類(構(gòu)成Java平臺核心API的運行時類)
D:\Java\jdk1.8.0_74\jre\lib\sunrsasign.jar;
D:\Java\jdk1.8.0_74\jre\lib\jsse.jar;// Java 安全套接字?jǐn)U展類庫头岔,用于實現(xiàn)加密的 Socket 連接
D:\Java\jdk1.8.0_74\jre\lib\jce.jar;// Java 加密擴展類庫,含有很多非對稱加密算法在里面鼠证,也是可擴展的
D:\Java\jdk1.8.0_74\jre\lib\charsets.jar; // Java 字符集,這個類庫中包含 Java 所有支持字符集的字符
D:\Java\jdk1.8.0_74\jre\lib\jfr.jar;// Java飛行記錄器 Flight Recorder靠抑,可以深入分析問題量九,使用參考
D:\Java\jdk1.8.0_74\jre\classes

java -verbose[:class|gc|jni]

  1. java -verbose:class 輸出虛擬機裝入的類的信息,顯示的信息格式如下
[Opened D:\Java\jdk1.8.0_74\jre\lib\rt.jar]
[Loaded java.lang.Object from D:\Java\jdk1.8.0_74\jre\lib\rt.jar]
[Loaded java.io.Serializable from D:\Java\jdk1.8.0_74\jre\lib\rt.jar]
[Loaded java.lang.Comparable from D:\Java\jdk1.8.0_74\jre\lib\rt.jar]
[Loaded java.util.Arrays from D:\Java\jdk1.8.0_74\jre\lib\rt.jar]
[Loaded java.nio.charset.Charset$ExtendedProviderHolder from D:\Java\jdk1.8.0_74\jre\lib\rt.jar]
[Loaded java.nio.charset.Charset$ExtendedProviderHolder$1 from D:\Java\jdk1.8.0_74\jre\lib\rt.jar]
...
[Loaded java.lang.Class$MethodArray from D:\Java\jdk1.8.0_74\jre\lib\rt.jar]
[Loaded java.lang.Void from D:\Java\jdk1.8.0_74\jre\lib\rt.jar]
current classLoader:sun.misc.Launcher$AppClassLoader@18b4aac2
parent classLoader:sun.misc.Launcher$ExtClassLoader@4554617c
grandparent classLoader:null
[Loaded java.lang.Shutdown from D:\Java\jdk1.8.0_74\jre\lib\rt.jar]
[Loaded java.lang.Shutdown$Lock from D:\Java\jdk1.8.0_74\jre\lib\rt.jar]
  1. java -verbose:gc 監(jiān)視虛擬機內(nèi)存回收的情況颂碧,格式如輸出所示
  public static void showGCInfo(){
    LookForClassLoader obj = new LookForClassLoader();
    System.gc();
  }

Output:
[GC (System.gc()) 2663K->672K(125952K), 0.0082196 secs]
[Full GC (System.gc()) 672K->569K(125952K), 0.0158595 secs]
箭頭前后的數(shù)據(jù)672K和569K分別表示垃圾收集GC前后所有存活對象使用的內(nèi)存容量荠列,說明有672K-569K=103K的對象容量被回收,括號內(nèi)的數(shù)據(jù)125952K為堆內(nèi)存的總?cè)萘吭爻牵占枰臅r間是0.0158595 秒(這個時間在每次執(zhí)行的時候會有所不同)

在VM的啟動參數(shù)中加入-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime肌似,分別輸出GC的簡要信息,GC的詳細(xì)信息诉瓦、GC的時間信息及GC造成的應(yīng)用暫停的時間川队。

GC輸出信息分析參考 | 官方文檔

  1. java -verbose:jni 輸出native方法調(diào)用的情況,一般用于診斷jni調(diào)用錯誤信息睬澡,格式如下:
[Dynamic-linking native method java.lang.Object.registerNatives ... JNI]
[Registering JNI native method java.lang.Object.hashCode]
[Registering JNI native method java.lang.Object.wait]
[Registering JNI native method java.lang.Object.notify]
[Registering JNI native method java.lang.Object.notifyAll]
[Registering JNI native method java.lang.Object.clone]
[Dynamic-linking native method java.lang.System.registerNatives ... JNI]
[Registering JNI native method java.lang.System.currentTimeMillis]
[Registering JNI native method java.lang.System.nanoTime]
[Registering JNI native method java.lang.System.arraycopy]
[Dynamic-linking native method java.lang.Thread.registerNatives ... JNI]
[Registering JNI native method java.lang.Thread.start0]
[Registering JNI native method java.lang.Thread.stop0]
[Registering JNI native method java.lang.Thread.isAlive]
[Registering JNI native method java.lang.Thread.suspend0]
[Registering JNI native method java.lang.Thread.resume0]
...

“貓”的后續(xù)
JVM 的后續(xù)

參考博客:
https://www.cnblogs.com/jingmoxukong/p/8258837.html?utm_source=gold_browser_extension
https://my.oschina.net/zhengjian/blog/133836
https://www.cnblogs.com/z00377750/p/9167768.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末固额,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子煞聪,更是在濱河造成了極大的恐慌斗躏,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昔脯,死亡現(xiàn)場離奇詭異啄糙,居然都是意外死亡,警方通過查閱死者的電腦和手機云稚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門隧饼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人碱鳞,你說我怎么就攤上這事桑李。” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵贵白,是天一觀的道長率拒。 經(jīng)常有香客問我,道長禁荒,這世上最難降的妖魔是什么猬膨? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮呛伴,結(jié)果婚禮上勃痴,老公的妹妹穿的比我還像新娘。我一直安慰自己热康,他們只是感情好沛申,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著姐军,像睡著了一般铁材。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上奕锌,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天著觉,我揣著相機與錄音,去河邊找鬼惊暴。 笑死饼丘,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的辽话。 我是一名探鬼主播肄鸽,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼屡穗!你這毒婦竟也來了贴捡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤村砂,失蹤者是張志新(化名)和其女友劉穎烂斋,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體础废,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡汛骂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了评腺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片帘瞭。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蒿讥,靈堂內(nèi)的尸體忽然破棺而出蝶念,到底是詐尸還是另有隱情抛腕,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布媒殉,位于F島的核電站担敌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏廷蓉。R本人自食惡果不足惜全封,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望桃犬。 院中可真熱鬧刹悴,春花似錦、人聲如沸攒暇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扯饶。三九已至恒削,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尾序,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工躯砰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留每币,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓琢歇,卻偏偏與公主長得像兰怠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子李茫,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容