程序猿:看懂這篇“JVM”文章后,你再?zèng)Q定以后的路該怎么走瓣颅?

做java開發(fā)的幾乎都知道jvm這個(gè)名詞管挟,但是由于jvm對(duì)實(shí)際的簡單開發(fā)的來說關(guān)聯(lián)的還是不多,一般工作個(gè)一兩年(當(dāng)然不包括愛學(xué)習(xí)的及專門做性能優(yōu)化的什么的)弄捕,很少有人能很好的去學(xué)習(xí)及理解什么是jvm僻孝,個(gè)人認(rèn)為這塊還是非常有必要去認(rèn)真了解及學(xué)習(xí)的导帝,這是java的基石。

JVM是什么穿铆?

JVM是Java Virtual Machine(Java虛擬機(jī))的縮寫您单,JVM是一種用于計(jì)算設(shè)備的規(guī)范,它是一個(gè)虛構(gòu)出來的計(jì)算機(jī)荞雏,是通過在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來實(shí)現(xiàn)的虐秦。

對(duì)于JVM的學(xué)習(xí),在我看來這么幾個(gè)部分最重要:

Java代碼編譯和執(zhí)行的整個(gè)過程

JVM內(nèi)存管理及垃圾回收機(jī)制

Java代碼編譯和執(zhí)行的整個(gè)過程

Java代碼編譯是由Java源碼編譯器來完成凤优,流程圖如下所示:

Java字節(jié)碼的執(zhí)行是由JVM執(zhí)行引擎來完成悦陋,流程圖如下所示:

Java代碼編譯和執(zhí)行的整個(gè)過程包含了以下三個(gè)重要的機(jī)制:

Java源碼編譯機(jī)制

類加載機(jī)制

類執(zhí)行機(jī)制

如果大家有想學(xué)習(xí)了解的,可以加入我的Java高級(jí)架構(gòu)進(jìn)階學(xué)習(xí)群:671017482

Java源碼編譯機(jī)制

Java 源碼編譯由以下三個(gè)過程組成:(javac –verbose 輸出有關(guān)編譯器正在執(zhí)行的操作的消息)

分析和輸入到符號(hào)表

注解處理

語義分析和生成class文件

最后生成的class文件由以下部分組成:

結(jié)構(gòu)信息筑辨。包括class文件格式版本號(hào)及各部分的數(shù)量與大小的信息

元數(shù)據(jù)俺驶。對(duì)應(yīng)于Java源碼中聲明與常量的信息。包含類/繼承的超類/實(shí)現(xiàn)的接口的聲明信息棍辕、域與方法聲明信息和常量池

方法信息暮现。對(duì)應(yīng)Java源碼中語句和表達(dá)式對(duì)應(yīng)的信息。包含字節(jié)碼楚昭、異常處理器表栖袋、求值棧與局部變量區(qū)大小、求值棧的類型記錄抚太、調(diào)試符號(hào)信息

類加載機(jī)制

JVM的類加載是通過ClassLoader及其子類來完成的塘幅,類的層次關(guān)系和加載順序可以由下圖來描述:

1)Bootstrap ClassLoader /啟動(dòng)類加載器

$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++實(shí)現(xiàn)尿贫,不是ClassLoader子類

2)Extension ClassLoader/擴(kuò)展類加載器

負(fù)責(zé)加載java平臺(tái)中擴(kuò)展功能的一些jar包电媳,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包

3)App ClassLoader/ 系統(tǒng)類加載器

負(fù)責(zé)記載classpath中指定的jar包及目錄中class

4)Custom ClassLoader/用戶自定義類加載器(java.lang.ClassLoader的子類)

屬于應(yīng)用程序根據(jù)自身需要自定義的ClassLoader畔塔,如tomcat仿野、jboss都會(huì)根據(jù)j2ee規(guī)范自行實(shí)現(xiàn)ClassLoader

加載過程中會(huì)先檢查類是否被已加載稍算,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查身冀,只要某個(gè)classloader已加載就視為已加載此類,保證此類只所有ClassLoader加載一次括享。而加載的順序是自頂向下搂根,也就是由上層來逐層嘗試加載此類。

類執(zhí)行機(jī)制

JVM是基于棧的體系結(jié)構(gòu)來執(zhí)行class字節(jié)碼的铃辖。線程創(chuàng)建后剩愧,都會(huì)產(chǎn)生程序計(jì)數(shù)器(PC)和棧(Stack),程序計(jì)數(shù)器存放下一條要執(zhí)行的指令在方法內(nèi)的偏移量娇斩,棧中存放一個(gè)個(gè)棧幀仁卷,每個(gè)棧幀對(duì)應(yīng)著每個(gè)方法的每次調(diào)用穴翩,而棧幀又是有局部變量區(qū)和操作數(shù)棧兩部分組成,局部變量區(qū)用于存放方法中的局部變量和參數(shù)锦积,操作數(shù)棧中用于存放方法執(zhí)行過程中產(chǎn)生的中間結(jié)果芒帕。

內(nèi)存管理和垃圾回收

JVM內(nèi)存組成結(jié)構(gòu)

JVM棧由堆、棧丰介、本地方法棧背蟆、方法區(qū)等部分組成,結(jié)構(gòu)圖如下所示:

JVM內(nèi)存回收

Sun的JVMGenerationalCollecting(垃圾回收)原理是這樣的:把對(duì)象分為年青代(Young)哮幢、年老代(Tenured)带膀、持久代(Perm),對(duì)不同生命周期的對(duì)象使用不同的算法橙垢。(基于對(duì)對(duì)象生命周期分析)

1.Young(年輕代)

年輕代分三個(gè)區(qū)垛叨。一個(gè)Eden區(qū),兩個(gè)Survivor區(qū)钢悲。大部分對(duì)象在Eden區(qū)中生成点额。當(dāng)Eden區(qū)滿時(shí),還存活的對(duì)象將被復(fù)制到Survivor區(qū)(兩個(gè)中的一個(gè))莺琳,當(dāng)這個(gè)Survivor區(qū)滿時(shí)还棱,此區(qū)的存活對(duì)象將被復(fù)制到另外一個(gè)Survivor區(qū),當(dāng)這個(gè)Survivor去也滿了的時(shí)候惭等,從第一個(gè)Survivor區(qū)復(fù)制過來的并且此時(shí)還存活的對(duì)象珍手,將被復(fù)制年老區(qū)(Tenured。需要注意辞做,Survivor的兩個(gè)區(qū)是對(duì)稱的琳要,沒先后關(guān)系,所以同一個(gè)區(qū)中可能同時(shí)存在從Eden復(fù)制過來對(duì)象秤茅,和從前一個(gè)Survivor復(fù)制過來的對(duì)象稚补,而復(fù)制到年老區(qū)的只有從第一個(gè)Survivor去過來的對(duì)象。而且框喳,Survivor區(qū)總有一個(gè)是空的课幕。

2.Tenured(年老代)

年老代存放從年輕代存活的對(duì)象。一般來說年老代存放的都是生命期較長的對(duì)象五垮。

3.Perm(持久代)

用于存放靜態(tài)文件乍惊,如今Java類、方法等放仗。持久代對(duì)垃圾回收沒有顯著影響润绎,但是有些應(yīng)用可能動(dòng)態(tài)生成或者調(diào)用一些class,例如Hibernate等,在這種時(shí)候需要設(shè)置一個(gè)比較大的持久代空間來存放這些運(yùn)行過程中新增的類莉撇。持久代大小通過-XX:MaxPermSize=進(jìn)行設(shè)置呢蛤。

舉個(gè)例子:當(dāng)在程序中生成對(duì)象時(shí),正常對(duì)象會(huì)在年輕代中分配空間稼钩,如果是過大的對(duì)象也可能會(huì)直接在年老代生成(據(jù)觀測(cè)在運(yùn)行某程序時(shí)候每次會(huì)生成一個(gè)十兆的空間用收發(fā)消息顾稀,這部分內(nèi)存就會(huì)直接在年老代分配)。年輕代在空間被分配完的時(shí)候就會(huì)發(fā)起內(nèi)存回收坝撑,大部分內(nèi)存會(huì)被回收静秆,一部分幸存的內(nèi)存會(huì)被拷貝至Survivor的from區(qū),經(jīng)過多次回收以后如果from區(qū)內(nèi)存也分配完畢巡李,就會(huì)也發(fā)生內(nèi)存回收然后將剩余的對(duì)象拷貝至to區(qū)抚笔。等到to區(qū)也滿的時(shí)候,就會(huì)再次發(fā)生內(nèi)存回收然后把幸存的對(duì)象拷貝至年老區(qū)侨拦。

通常我們說的JVM內(nèi)存回收總是在指堆內(nèi)存回收殊橙,確實(shí)只有堆中的內(nèi)容是動(dòng)態(tài)申請(qǐng)分配的,所以以上對(duì)象的年輕代和年老代都是指的JVM的Heap空間狱从,而持久代則是之前提到的MethodArea膨蛮,不屬于Heap。

現(xiàn)在我們就通過一個(gè)具體的例子來分析它的運(yùn)行過程季研。

虛擬機(jī)通過調(diào)用某個(gè)指定類的方法main啟動(dòng)敞葛,傳遞給main一個(gè)字符串?dāng)?shù)組參數(shù),使指定的類被裝載与涡,同時(shí)鏈接該類所使用的其它的類型惹谐,并且初始化它們。新建一java源文件并取名HelloApp.java驼卖,內(nèi)容如下:

class HelloApp {

public static void main(String[] args) {

System.out.println("Hello World!");

for (int i = 0; i < args.length; i++ ) {

System.out.println(args);

}

}

}

在命令模式下輸入:javac HelloApp.java 進(jìn)行編譯氨肌,這時(shí)同目錄下會(huì)產(chǎn)生一個(gè)編譯后的文件:HelloApp.class

然后在命令行模式下鍵入:java HelloApp run virtual machine

將通過調(diào)用HelloApp的方法main來啟動(dòng)java虛擬機(jī),傳遞給main一個(gè)包含三個(gè)字符串"run"酌畜、"virtual"怎囚、"machine"的數(shù)組。我們略述虛擬機(jī)在執(zhí)行HelloApp時(shí)可能采取的步驟桥胞。

JVM虛擬機(jī)運(yùn)行過程

開始試圖執(zhí)行類HelloApp的main方法恳守,發(fā)現(xiàn)該類并沒有被裝載,也就是說虛擬機(jī)當(dāng)前不包含該類的二進(jìn)制代表埠戳,于是虛擬機(jī)使用ClassLoader試圖尋找這樣的二進(jìn)制代表井誉。如果這個(gè)進(jìn)程失敗蕉扮,則拋出一個(gè)異常整胃。類被裝載后同時(shí)在main方法被調(diào)用之前,必須對(duì)類HelloApp與其它類型進(jìn)行鏈接然后初始化喳钟。

鏈接包含三個(gè)階段:檢驗(yàn)屁使,準(zhǔn)備和解析在岂。

檢驗(yàn)檢查被裝載的主類的符號(hào)和語義,準(zhǔn)備則創(chuàng)建類或接口的靜態(tài)域以及把這些域初始化為標(biāo)準(zhǔn)的默認(rèn)值蛮寂,解析負(fù)責(zé)檢查主類對(duì)其它類或接口的符號(hào)引用蔽午,在這一步它是可選的。類的初始化是對(duì)類中聲明的靜態(tài)初始化函數(shù)和靜態(tài)域的初始化構(gòu)造方法的執(zhí)行酬蹋。一個(gè)類在初始化之前它的父類必須被初始化及老。

哇哇咔,過完一個(gè)周末到現(xiàn)在還沒有緩過勁來范抓,你們有想特別了解的那些技術(shù)點(diǎn)嗎骄恶?

——源碼分析、Spring 企業(yè)級(jí)開發(fā)前瞻匕垫,持久層僧鲁,高性能/高并發(fā),分布式協(xié)調(diào)技術(shù) zookeeper 服務(wù)鎖象泵,Nosql寞秃,高可用性/可擴(kuò)展,分布式架構(gòu)介紹偶惠,服務(wù)調(diào)用春寿,性能優(yōu)化,JVM優(yōu)化洲鸠,數(shù)據(jù)庫優(yōu)化堂淡,服務(wù)器優(yōu)化,雙十一電商項(xiàng)目實(shí)戰(zhàn)(用戶認(rèn)證系統(tǒng)扒腕,商品管理系統(tǒng)绢淀,訂單系統(tǒng),支付系統(tǒng)等等)

留言給我瘾腰,我會(huì)優(yōu)先更新的皆的,也可以加我的群:671017482,群公告有大量的視頻教程蹋盆,謝謝大家费薄!


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市栖雾,隨后出現(xiàn)的幾起案子楞抡,更是在濱河造成了極大的恐慌,老刑警劉巖析藕,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件召廷,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)竞慢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門先紫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人筹煮,你說我怎么就攤上這事遮精。” “怎么了败潦?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵本冲,是天一觀的道長。 經(jīng)常有香客問我劫扒,道長眼俊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任粟关,我火速辦了婚禮疮胖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘闷板。我一直安慰自己澎灸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布遮晚。 她就那樣靜靜地躺著性昭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪县遣。 梳的紋絲不亂的頭發(fā)上糜颠,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音萧求,去河邊找鬼其兴。 笑死,一個(gè)胖子當(dāng)著我的面吹牛夸政,可吹牛的內(nèi)容都是我干的元旬。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼守问,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼匀归!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起耗帕,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤穆端,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后仿便,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體体啰,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡字柠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了狡赐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡钦幔,死狀恐怖枕屉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鲤氢,我是刑警寧澤搀擂,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站卷玉,受9級(jí)特大地震影響哨颂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜相种,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一威恼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寝并,春花似錦箫措、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至镀岛,卻和暖如春弦牡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背漂羊。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來泰國打工驾锰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人走越。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓稻据,卻偏偏與公主長得像,于是被迫代替她去往敵國和親买喧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子捻悯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

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