Java之JVM

談到JVM轧坎,對于很多干了三四年的程序員來說,還是很模糊竿奏。我待了好幾個公司袄简,問過很多干了3-5年Java開發(fā)的同事,大部分人其實對于JVM理解都不深(當然對于我自己來說泛啸,也是一樣)。JVM相當于一個武林高手的內(nèi)功秃症,內(nèi)功強大才是真的強候址,所以我用本文整理出來JVM的重點知識。

JVM總體分為四大塊种柑,每一塊都有大量的細節(jié)內(nèi)容說岗仑,這里只做主干梳理

一,類的加載機制

1.什么是類的加載

類的加載指的是將類的.class文件中的二進制數(shù)據(jù)讀入到內(nèi)存中聚请,將其放在運行時數(shù)據(jù)區(qū)的方法區(qū)內(nèi)荠雕,然后在堆區(qū)創(chuàng)建一個java.lang.Class對象,用來封裝類在方法區(qū)的數(shù)據(jù)結(jié)構(gòu)驶赏。類的加載最終是位于堆區(qū)中的Class對象炸卑,Class對象封裝了類在方法區(qū)的數(shù)據(jù)結(jié)構(gòu),并且向程序員提供了訪問方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)的接口

2.類的生命周期

類的生命周期包括這幾個部分煤傍,加載盖文、連接、初始化蚯姆、使用和卸載五续。前三步是類的加載過程洒敏,如下圖

其中 驗證,準備疙驾,解析 為連接部分

加載:查找并加載類的二進制數(shù)據(jù)凶伙,在Java堆中也創(chuàng)建一個java.lang.Class類的對象

連接:連接又包含三塊內(nèi)容:驗證、準備它碎、解析函荣。1)驗證,文件格式链韭、元數(shù)據(jù)偏竟、字節(jié)碼、符號引用驗證敞峭;2)準備踊谋,為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認值旋讹;3)解析殖蚕,把類中的符號引用轉(zhuǎn)換為直接引用

初始化:為類的靜態(tài)變量賦予正確的初始值

使用:new出對象在程序中使用

卸載:執(zhí)行垃圾回收

3.類加載器與雙親委派模型

從虛擬機角度看,只存在2種類加載器

一種是啟動類加載器(Bootstrap ClassLoader)沉迹,使用C++實現(xiàn)的睦疫,是虛擬機本身的一種。

一種是其他的類加載器鞭呕,使用Java實現(xiàn)蛤育,獨立于虛擬機,繼承于java.lang.ClassLoader葫松。

從Java開發(fā)者的角度看瓦糕,類加載器可以進一步劃分,一般情況分為3種

第一種:啟動類加載器(Bootstrap ClassLoader) 腋么,這個類加載器負責將存放在<JAVA_HOME>\lib目錄下的咕娄,或被-Xbootclasspath參數(shù)所制定的路徑種的,并且是被虛擬機識別的類庫加載到虛擬機內(nèi)存中啟動類加載器無法被Java程序直接引用珊擂,用戶在編寫自定義類加載器時圣勒,如果需要加載請求委派到引導(dǎo)類加載器,可直接使用null代替即可摧扇。

第二種:擴展類加載器(Extension ClassLoader) 圣贸,該加載器由sun.misc.Lanucher$ExtClassLoader實現(xiàn),負責加載<JAVA_HOME>\lib\ext目錄中扳剿,或者被java.ext.dirs系統(tǒng)變量指定路徑中的類庫藏鹊,開發(fā)者可以直接使用擴展類加載器

第三種:應(yīng)用程序類加載器<Application ClassLoader>踱蠢, 該類是ClassLoader中g(shù)etSystemClassLoader()方法返回值障本,所以一般稱為系統(tǒng)類加載器。負責加載用戶類路徑(ClassPath)上所指定的類庫橙困,開發(fā)者可以直接使用這個類加載器,如果應(yīng)用程序沒有自定義類加載器耕餐,一般情況下是默認的類加載器

為什么采用雙親委派模型凡傅,如圖

除啟動類加載器外,所有其它類加載器都有其父類加載器肠缔。如果一個類加載器收到了類加載請求夏跷,它不會首先加載這個類,而是將請求委派給父類加載器去完成所有的加載請求最終都委派給頂層的引導(dǎo)類加載器明未,只有當父類加載器無法完成加載請求(也就是搜索范圍內(nèi)無該類)子加載器才會嘗試自己去加載這個類

——使得Java類隨著類加載器不同而具備帶優(yōu)先級的層次關(guān)系槽华,如java.lang.Object(位于rt.jar內(nèi)),無論那個類加載器要加載該類趟妥,最終都委派給頂層引導(dǎo)類加載器猫态,因此Object類在程序的各種類加載環(huán)境中都是同一個類。

——如果沒有雙親委派披摄,用戶自定義重名的類亲雪,將會使得系統(tǒng)帶有多個同名的類,使得基礎(chǔ)的Java類型體系混亂雙親委派模型對于保證Java程序的穩(wěn)定運行十分重要疚膊,它實現(xiàn)卻很簡單首先檢查是否被加載過义辕,若沒有加載則調(diào)用父類加載器的loadClass方法,若父類加載器為空寓盗,則默認使用引導(dǎo)類加載器作為父類加載器灌砖,如果加載失敗,則調(diào)用自身的findClass()方法加載

——破壞雙親委派情形:使用JNDI服務(wù)傀蚌、代碼模塊熱部署

二周崭,JVM內(nèi)存結(jié)構(gòu)

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

方法區(qū)和堆是所有線程共享的內(nèi)存區(qū)域;java棧喳张、本地方法棧和程序計數(shù)器是運行線程私有的內(nèi)存區(qū)域。

Java堆(Heap):是Java虛擬機所管理的內(nèi)存中最大的一塊美澳。Java堆是被所有線程共享的一塊內(nèi)存區(qū)域销部,在虛擬機啟動時創(chuàng)建。此內(nèi)存區(qū)域的唯一目的就是存放對象實例制跟,幾乎所有的對象實例都在這里分配內(nèi)存舅桩。

方法區(qū)(Method Area):方法區(qū)(Method Area)與Java堆一樣,是各個線程共享的內(nèi)存區(qū)域雨膨,它用于存儲已被虛擬機加載的類信息擂涛、常量、靜態(tài)變量聊记、即時編譯器編譯后的代碼等數(shù)據(jù)撒妈。

程序計數(shù)器(Program Counter Register):程序計數(shù)器(Program Counter Register)是一塊較小的內(nèi)存空間恢暖,它的作用可以看做是當前線程所執(zhí)行的字節(jié)碼的行號指示器。

JVM棧(JVM Stacks):與程序計數(shù)器一樣狰右,Java虛擬機棧(Java Virtual Machine Stacks)也是線程私有的杰捂,它的生命周期與線程相同。虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法被執(zhí)行的時候都會同時創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表棋蚌、操作棧嫁佳、動態(tài)鏈接、方法出口等信息谷暮。每一個方法被調(diào)用直至執(zhí)行完成的過程蒿往,就對應(yīng)著一個棧幀在虛擬機棧中從入棧到出棧的過程。

本地方法棧(Native Method Stacks):本地方法棧(Native Method Stacks)與虛擬機棧所發(fā)揮的作用是非常相似的湿弦,其區(qū)別不過是虛擬機棧為虛擬機執(zhí)行Java方法(也就是字節(jié)碼)服務(wù)瓤漏,而本地方法棧則是為虛擬機使用到的Native方法服務(wù)。

2.對象分配規(guī)則

JVM區(qū)域大體分為兩個區(qū)域省撑,如上圖

對象優(yōu)先分配在Eden區(qū)赌蔑,如果Eden區(qū)沒有足夠的空間時,虛擬機執(zhí)行一次Minor?GC竟秫。

大對象直接進入老年代(大對象是指需要大量連續(xù)內(nèi)存空間的對象)娃惯。這樣做的目的是避免在Eden區(qū)和兩個Survivor區(qū)之間發(fā)生大量的內(nèi)存拷貝(新生代采用復(fù)制算法收集內(nèi)存)。

長期存活的對象進入老年代肥败。虛擬機為每個對象定義了一個年齡計數(shù)器趾浅,如果對象經(jīng)過了1次Minor?GC那么對象會進入Survivor區(qū),之后每經(jīng)過一次Minor?GC那么對象的年齡加1馒稍,知道達到閥值對象進入老年區(qū)皿哨。

動態(tài)判斷對象的年齡。如果Survivor區(qū)中相同年齡的所有對象大小的總和大于Survivor空間的一半纽谒,年齡大于或等于該年齡的對象可以直接進入老年代证膨。

空間分配擔保。每次進行Minor?GC時鼓黔,JVM會計算Survivor區(qū)移至老年區(qū)的對象的平均大小央勒,如果這個值大于老年區(qū)的剩余值大小則進行一次Full?GC,如果小于檢查HandlePromotionFailure設(shè)置澳化,如果true則只進行Monitor?GC,如果false則進行Full?GC崔步。

三,GC算法 垃圾回收

1.對象存活判斷

判斷對象是否存活一般有兩種方式:

引用計數(shù):每個對象有一個引用計數(shù)屬性缎谷,新增一個引用時計數(shù)加1井濒,引用釋放時計數(shù)減1,計數(shù)為0時可以回收。此方法雖然簡單瑞你,但是無法解決對象相互循環(huán)引用的問題酪惭。

可達性分析(Reachability Analysis):從GC Roots開始向下搜索,搜索走過的路徑稱為引用鏈捏悬。當一個對象到GC Roots沒有任何引用鏈相連時撞蚕,則證明此對象是不可用的,為不可達對象过牙。

2.GC算法

GC最基礎(chǔ)的算法有三種:標記 -清除算法甥厦、復(fù)制算法標記-壓縮算法

我們常用的垃圾回收器一般都采用分代收集算法寇钉。

標記 -清除算法:“標記-清除”(Mark-Sweep)算法刀疙,如它的名字一樣,算法分為“標記”和“清除”兩個階段:首先標記出所有需要回收的對象扫倡,在標記完成后統(tǒng)一回收掉所有被標記的對象谦秧。

復(fù)制算法:“復(fù)制”(Copying)的收集算法,它將可用內(nèi)存按容量劃分為大小相等的兩塊撵溃,每次只使用其中的一塊疚鲤。當這一塊的內(nèi)存用完了,就將還存活著的對象復(fù)制到另外一塊上面缘挑,然后再把已使用過的內(nèi)存空間一次清理掉集歇。

標記-壓縮算法:標記過程仍然與“標記-清除”算法一樣,但后續(xù)步驟不是直接對可回收對象進行清理语淘,而是讓所有存活的對象都向一端移動诲宇,然后直接清理掉端邊界以外的內(nèi)存分代收集算法

分代收集(Generational Collection)算法:把Java堆分為新生代和老年代,這樣就可以根據(jù)各個年代的特點采用最適當?shù)氖占惴ā?/p>

3.垃圾回收器

Serial收集器:串行收集器是最古老惶翻,最穩(wěn)定以及效率高的收集器姑蓝,可能會產(chǎn)生較長的停頓,只使用一個線程去回收吕粗。

ParNew收集器:ParNew收集器其實就是Serial收集器的多線程版本纺荧。

Parallel收集器:Parallel Scavenge收集器類似ParNew收集器,Parallel收集器更關(guān)注系統(tǒng)的吞吐量颅筋。

Parallel Old 收集器:Parallel Old是Parallel Scavenge收集器的老年代版本虐秋,使用多線程和“標記-清理”算法

CMS收集器:CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。

G1收集器:G1 (Garbage-First)是一款面向服務(wù)器的垃圾收集器,主要針對配備多顆處理器及大容量內(nèi)存的機器. 以極高概率滿足GC停頓時間要求的同時,還具備高吞吐量性能特征

四垃沦,GC調(diào)優(yōu)

1.調(diào)優(yōu)工具

常用調(diào)優(yōu)工具分為兩類

JDK自帶監(jiān)控工具:JconsoleJvisualvm

第三方:MAT(Memory Analyzer Tool)GChisto

Jconsole用押,Java Monitoring and Management Console?是從java5開始肢簿,在JDK中自帶的java監(jiān)控和管理控制臺,用于對JVM中內(nèi)存,線程和類等的監(jiān)控?

?Jvisualvm池充,jdk自帶全能工具桩引,可以分析內(nèi)存快照、線程快照收夸;監(jiān)控內(nèi)存變化坑匠、GC變化等。

MAT卧惜,Memory Analyzer Tool厘灼,一個基于Eclipse的內(nèi)存分析工具,是一個快速咽瓷、功能豐富的Java heap分析工具设凹,它可以幫助我們查找內(nèi)存泄漏和減少內(nèi)存消耗

GChisto,一款專業(yè)分析gc日志的工具

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茅姜,一起剝皮案震驚了整個濱河市闪朱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌钻洒,老刑警劉巖奋姿,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異素标,居然都是意外死亡称诗,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門糯钙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粪狼,“玉大人,你說我怎么就攤上這事任岸≡匍” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵享潜,是天一觀的道長困鸥。 經(jīng)常有香客問我,道長剑按,這世上最難降的妖魔是什么疾就? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮艺蝴,結(jié)果婚禮上猬腰,老公的妹妹穿的比我還像新娘。我一直安慰自己猜敢,他們只是感情好姑荷,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布盒延。 她就那樣靜靜地躺著,像睡著了一般鼠冕。 火紅的嫁衣襯著肌膚如雪添寺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天懈费,我揣著相機與錄音计露,去河邊找鬼。 笑死憎乙,一個胖子當著我的面吹牛票罐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播寨闹,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼胶坠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了繁堡?” 一聲冷哼從身側(cè)響起沈善,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎椭蹄,沒想到半個月后闻牡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡绳矩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年罩润,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翼馆。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡割以,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出应媚,到底是詐尸還是另有隱情严沥,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布中姜,位于F島的核電站消玄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏丢胚。R本人自食惡果不足惜翩瓜,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望携龟。 院中可真熱鬧兔跌,春花似錦、人聲如沸峡蟋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至桦卒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間匿又,已是汗流浹背方灾。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留碌更,地道東北人裕偿。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像痛单,于是被迫代替她去往敵國和親嘿棘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

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

  • 一. JVM JVM是Java Virtual Machine(Java虛擬機)的縮寫旭绒,也就是指的JVM虛擬機鸟妙,是...
    大鵬的鵬閱讀 925評論 1 0
  • 面試專題我放在git上了,地址Github 歡迎fork然后一起更新 1. 內(nèi)存模型以及分區(qū)挥吵,需要詳細到每個區(qū)放什...
    hloong閱讀 1,817評論 3 4
  • 1.JVM的架構(gòu) 說明: Java棧重父,程序計數(shù)器,本地方法棧是線程獨享的方法區(qū)忽匈,堆是線程共享的 2.常用GC算法 ...
    zhglance閱讀 376評論 0 2
  • go runtime和java jvm之間的共同點就是GC房午,通過兩者的對比,可以更加深入理解兩者丹允。 go runt...
    Wu杰語閱讀 1,518評論 0 1
  • 參考博客:1 2 3 JVM工作原理 java虛擬機體系結(jié)構(gòu)Java平臺由Java虛擬機和Java應(yīng)用程序接口搭建...
    小明今晚加班閱讀 957評論 0 33