故事:走進JVM的世界(圖文並茂)

原文:故事:走進JVM的世界(圖文並茂)git

走進JVM的世界

  1. 注意!本文較長,建議先收藏再閱讀。更多文章能夠關注做者公衆號:碼上實戰
  2. 你也能夠 star 個人 GitHub上本文所屬倉庫:https://github.com/flyhero/Ma...
  3. 說明:本文在 Java 8 Hotspot 64位操做系統下構思

小強是一個工做3年有餘的開發工程師,從他的髮量你就能夠知道,小強資歷還尚淺。程序員

程序員驚人髮量

最近公司沒什麼事,他也開始無聊起來了。這天下午,同事們在激烈的討論這業務,但他沒有參與,因而他決定學習些什麼知識,無聊的翻着各個網頁,發現JVM是各位大神們推薦過的知識,因而決定好好看一看。github

5分鐘事後……算法

小強感到這知識有些枯燥乏味,怪不得是大神們能看的!又看了幾分鐘,小強倦意襲來,揉了揉睡眼惺忪的眼睛。api

然而就在這一刻,他忽然發現周圍同事激烈討論的聲音聽不到了,安靜到了極致。安全

1. 入界

小強努力的睜開眼睛,才發現本身居然身處一個白茫茫的空間中,嚇得一跳,心想我這是怎麼了,穿越了?但穿越也得穿越到一我的間如畫,美女如雲的地方啊……,這境地……
JVM幻境微信

忽然前方走來一個白鬍子老頭,小強正想開口,老頭捷足先登:你好,我是這個JVM世界的締造者,你能夠叫我 「HotSpot」,不過這無所謂,由於我所創造的這個世界,是按照 「JVM規範」 來完成的。我正在休息時,發現來了一位客人,原來是你。併發

小強:我是想問……工具

老頭: 不用問,我知道,你是想了解一下我創造的這個世界吧!跟我來吧。佈局

這老頭,我還沒說話,這就結束了!好吧,跟你看看且說。

老頭邊走邊道:JVM 的世界 空間是有限的,咱們堅持一個原則 : 各司其職,不留無用之人!

小強: 啊!好殘酷。

老頭: 不,這不是殘酷,咱們這個世界生來就是爲客戶提供服務,爲客戶發光發熱的,每一個人奉獻出了本身的能力就是圓滿完成任務,退出舞臺是理所應當的,也是他們最好的歸宿。

小強:也是,這樣這個世界纔不會那麼擁擠,才能井井有理的工做,我怎麼這麼不開竅呢……

2. 佈局

過來,帶你先看看咱們世界的總體組成和中心區如何佈局。
總體佈局

先來看看咱們最主要的平常工做區(運行時數據區),爲了讓咱們工做起來更有效率,咱們將世界空間劃分爲這幾個板塊。

居住區-堆

這裏是人們工做外的居住區,居住區咱們基於人們的年齡也進一步分出了,伊甸區,倖存者區,老年區。
居住區

工做區-棧

每一個任務來臨時,都會在工做區單獨開闢出一個地方來用於完成這個任務。
棧幀

記錄者-程序計數器

因爲咱們同時能作的任務有限,因此咱們須要爲不一樣的任務劃分出不一樣的時間片,咱們在切換任務的時候,須要一個記錄者,可以記錄咱們這個任務作到了哪裏,下次回來可以繼續作。

倉庫管理區-方法區

這裏存放着工人的模板以及經常使用的不變的工具等。

3. 生與死

這裏工做的人們都會經歷生與死,大部分人們活不到老年,但這不重要,重要的是他爲咱們作出了貢獻。

3.1 出生

老頭:這裏的每一個人都有一個模板(類),看到那個正在居住區休息的高個嗎?他叫張三,他是根據外部客戶給定的模板 「 User Class」 創造的,他但是客戶最喜好的工人了。你知道客戶的這些模板(類)是如何進入的到咱們的世界中的嗎?

小強:這個我知道點,以前看過一點點。這個過程仍是有些複雜的,客戶的模板(類)是經過一個翻譯工廠(編譯器) 將它翻譯成class 字節碼,由於大家這個世界只認識字節碼,而後有大家的加載系統將它們加載到這裏。

加載過程當中有這些階段:
loading-class.png

其中加載階段是由加載器來完成的。

老頭:是的,咱們提供了三種工廠,啓動類加載器,擴展類加載器,應用類加載器,固然客戶也能夠自定義加載器。
parents-delegation.png

小強:他們遵循着雙親委派模型,可是我一直不太理解這個詞!

老頭: 這是因爲大家語言翻譯的問題致使,這個模式叫 「parents delegation」,知道了吧!它是指有你的父輩們來幫你完成。

小強:那雙親委派模式 有什麼好處呢?

老頭:

  1. 具備優先級層次的關係能夠避免模板(類)的重複加載
  2. 安全考慮能夠防止Java核心api被替換

老頭繼續道:那鏈接過程當中的三步,你知道是作什麼嗎?

小強:具體的我就不知道了哎……

老頭笑了笑:對於客戶定義的模板(類),咱們可不是來者不拒的,爲了咱們這個世界的安全以及能提供更好的服務,咱們會對模板作一些驗證及後續操做。

驗證包括格式驗證,元數據驗證,字節碼驗證,符號驗證。當驗證經過後,咱們會爲模板所依賴的東西(類變量)分配空間,最後將符號引用替換爲直接引用。

老頭看了看小強眉頭緊皺,因而繼續補充:你可能不瞭解什麼是符號引用和直接引用!

符號引用就是在編譯時,並不知道模板(類)所依賴的其餘東西,會在咱們的空間中的哪一個位置,只能用符號來表示。

直接引用就是 全部東西被加載到這裏後會有本身的真實空間地址,而後去替換符號引用。這樣運行時就能找到它們所依賴的東西了。

最後就是初始化了,這個階段主要是對類變量初始化,是執行類構造器的過程。

小強:我怎麼沒看到這些模板呢?

老頭:這些模板我把他們隱藏在世界的後方,大多數人是見不到的,他們統稱爲 Klass。

小強:不對啊!你是否是搞錯了?不該該叫 Class嗎?

老頭:哈哈!我剛纔說了,大多數人見不到,你就是其中之一啊!大家平時見到的 Class只是對 Klass的一種封裝而已,真正記錄模板中的具體元信息的就是 Klass。這回要記住了,年輕人。

3.2 工人

小強: 爲何你的工人是等量差的身高呢?
obj-data.png

老頭:你的觀察仍是挺仔細的嘛!是的,他們確實是等量差的,想要知道爲何,要先了解這些工人有哪些部分組成。
obj-length.png

它們頭部大小是固定的,身體大小是由本身的屬性數據決定的,而最後的腳部倒是我來決定的,若是前面兩個數據的大小沒有達到 8 的倍數,那麼我就會來填充,因此就是這裏的填充使得他們擁有了等量的身高差(內存對齊)。

我是基於兩點緣由來這個締造他們的:

  1. 平臺緣由:不是全部的硬件平臺都能訪問任意地址上的任意數據的;某些硬件平臺只能在某些地址處取某些特定類型的數據,不然拋出硬件異常。
  2. 性能緣由:中央大腦(CPU)訪問內存是有內存訪問粒度的,就是每次訪問內存的長度是固定的,若是不這樣作,那麼中央大腦起須要訪問兩次內存,而對齊後只須要一次。

小強:嗯,明白了!那能給我說說這些工人在居住區爲何要不斷的搬遷呢?

3.3 成長

老頭:通過長時間的觀察,我發現每一個工人的生命長短是不同的。因此我把居住區分爲新生代,老年代,而後讓他們合理的搬遷,這樣能有效的利用空間並且讓垃圾小分隊工做更有效率。
堆區分代
工人誕生後會分配到Eden區,當Eden區人員快滿時,垃圾小分隊會來清掃,清掃後若是工人還活着,那麼他們將搬遷至Survivor區中的其中一個,當這個Survivor快滿時,垃圾小分隊會將還活着的工人搬遷至另外一個Survivor區中,就這樣重複着,每經歷一次垃圾小分隊的清掃,活着的工人就會長大一歲,直到工人的年齡達到15歲,到達後會將他們搬遷至老年代生活的地方。但也有例外,若是某個工人吃的太胖,新生代容不下他,那麼他將直接去老年代住下。當老年代快住滿時,將會有垃圾大掃除(full gc)。

小強:原來如此啊!今後我不再是隻知道堆區棧區的菜鳥啦!哈哈哈哈……

老頭:小夥子,不要高興太早!你到目前爲止所瞭解的還是九牛一毛。

3.4 死亡證實

小強:如何肯定工人是否到達生命的盡頭呢?

第一種:引用計數法

給每一個工人添加一個引用計數器,就是隻要有人須要這個工人幫忙,那麼就給這個工人的計數加1,反之,別人再也不須要這個工人的幫忙,那麼計數就減1,直到這個計數爲0,那麼表示這個工人生命到了盡頭。

但這種方法有個問題:若是A工人和B工人相互須要幫忙,但沒有任何其餘工人或任務須要他們兩個,那麼他們兩個會永遠活下!因此這種方法咱們不會採起的。

第二種:可達性分析法

咱們找出被稱爲 「GC roots」的工人做爲起點,依次尋找他們工做中依賴的工人,這就能夠知道哪些工人是沒有必要在存在下去了。

小強:我怎麼知道哪些是 「GC roots」工人呢?

老頭:

  1. 工做區(棧)中的須要用到的工人
  2. 倉庫(方法區)中模板(類)自己須要的工人(靜態,常量)
  3. 世界後方(native方法)須要的工人

小強:Got it!

4. 回收

老頭:下面我帶你去認識一下垃圾小分隊的人物吧!不過在認識他們以前你最好了解一下,垃圾清除的基本方法論。

4.1 基本方法論

收集垃圾遵循的基本方法論有如下幾種:

  • 標記-清除

    首先標記出全部須要回收的工人(對象),在標記完成後統一回收全部被標記的工人。

    但這個有兩個缺點:1. 效率不高 2. 會產生許多碎片空間

  • 複製

    將可用的空間一分爲二,每次只使用其中一塊,當快使用完時,小分隊回收,而後將活着的工人搬遷至另外一塊。

    這雖然解決了標記-清除的效率問題,但此種方法卻縮小了一半空間。

  • 標記-整理

    首先標記出全部須要回收的工人(對象),而後將存活的工人移動到空間的一端,而後清理掉邊界之外的工人。

小強笑了笑:原來是這三種算法啊!我知道!

老頭:既然知道,那跟我來認識一下垃圾清掃隊的人吧!

4.2 主要成員

垃圾清掃隊有好幾個小隊組成,客戶喜歡哪一個小隊能夠指定讓誰來工做,他們各個隊伍的清掃方式各不相同也各有優劣。

我給你介紹一下兩個主要成員吧,CMS,G1兩個小隊出列。

CMS:到,咱們是CMS分隊,全稱叫 「Concurrent Mark Sweep」,顧名思義,咱們是採用標記清除算法的併發小分隊,咱們以獲取最短回收停頓時間爲目標。

小強:那你說說大家是如何工做的?

CMS:咱們主要分四個步驟工做,1. 初始標記 2.併發標記 3.從新標記 4.併發清除

小強:算啦,這麼多步驟太須要時間來了解了,我如今知道你的優勢了,那你的缺點有什麼呢?

CMS:這怎麼還帶揭人傷疤的……

老頭這時嚴肅的咳嗽了兩聲,其意CMS立馬捕獲到了,委屈的說:

我有三個缺點:

  1. 當資源不是很充足時,佔用過多的資源,致使任務變慢
  2. 沒法處理浮動垃圾,咱們清理的時候,工人同時也在工做,咱們標記後,正好有些工人不在須要了
  3. 咱們分隊遵循的是「標記-清除」算法,因此會產生大量碎片空間,致使世界大掃除(full gc)提早到來

心直口快的小強來了句:原來你的問題這麼嚴重,老頭居然沒把大家小分隊辭掉……

CMS:你…… 想當年咱們分隊但是紅極一時的……

那麼我猜G1是否是能夠彌補CMS的不足呢?

G1: 說實話,咱們分隊的目標就是替換CMS分隊…… (JDK14 CMS正式落下帷幕)

小強不懷好意的笑了起來,哈哈……,CMS翻着白眼躲到一旁的角落暗自傷感去了。

角落哭.jpeg

小強:那G1說說你的能耐吧!

G1: 咱們隊是基於標記整理算法的,所以不會產生大量碎片空間

  • 咱們同時引入了分區的思路,弱化了分代的概念
  • 咱們的停頓時間是可控的,可避免雪崩現象
  • 咱們也能充分利用客戶給咱們的資源,減小停頓時間

這是咱們隊的優點,接下來我給你詳細介紹下咱們隊的狀況……

小強:好的!你繼續……

迴歸

就在小強聽的興趣濃濃時,天空中忽然出現一隻巨大無比的手向他襲來,小強躲閃不開,啊……

巴掌.png

小強捂着本身的頭,有點恍惚,擡頭一看,擦,技術總監……你怎麼也在這?

總監:我不在這我在哪?在家睡大覺嗎!

這時小強纔回過神來,原來本身還在辦公室,大事不妙啊!

總監:小強,回家多爽,明天就不用來了吧!

小強一慌,腦殼靈機一動:總監,知道我剛纔在作什麼嗎?那可不是在睡覺,我有一個故事你且聽聽再作決定。

吧啦吧啦……

最後我將本文知識總結成了思惟導圖:
思惟導圖

說明:

  1. 【做者】:flyhero
  2. 【公衆號】:碼上實戰。
  3. 【簡介】:想作個擁有理論的實戰派。
  4. 【福利】:關注微信公衆號,回覆:「JVM」 獲取思惟導圖
  5. 【轉載】:轉載請說明出處,謝謝合做!
相關文章
相關標籤/搜索