架構師視角:對JVM架構進行解析

每一個Java 開發人員都知道字節碼由JRE (Java運行時環境)執行。但許多人不知道JRE是Java虛擬機(JVM)的實現, 它負責分析字節碼、解析并執行代碼。作為一個開發人員了解JVM架構是非常重要的,因為它使我們能更高效的編寫代碼。在這篇文章中我們將更深入了解Java中的JVM架構以及JVM的各個組件。

JVM是什么?

虛擬機 是物理機器的一個軟件實現。Java運行在VM上,實現WORA (一處編寫,處處運行)。 編譯器將Java文件編譯成Java .class 文件,然后這個.class文件被輸入到JVM中進行類文件的加載和執行。下面是一個JVM的架構圖。

JVM是如何工作的呢?

正如上面的架構圖所示,JVM被分為三個主要的子系統:

類加載器子系統

運行時數據區

執行引擎

1. 類加載器子系統

Java的動態類加載功能是由類加載器子系統處理。當它在運行時(不是編譯時)首次引用一個類時,它加載、鏈接并初始化該類文件。

1.1 加載

類由此組件加載。啟動類加載器 (Boot Strap class Loader)、擴展類加載器(Extension class Loader)和應用程序類加載器(Application class Loader) 這三種類加載器幫助完成類的加載。

啟動類加載器 – 負責從啟動類路徑中加載類,無非就是rt.jar。這個加載器會被賦予最高優先級。

擴展類加載器 – 負責加載ext 目錄(jre\lib)內的類.

應用程序類加載器 – 負責加載應用程序級別類路徑,涉及到路徑的環境變量等etc.

上述的類加載器會遵循委托層次算法(Delegation Hierarchy Algorithm)加載類文件。

1.2 鏈接

校驗 – 字節碼校驗器會校驗生成的字節碼是否正確,如果校驗失敗,我們會得到校驗錯誤。

準備 – 分配內存并初始化默認值給所有的靜態變量。

解析 – 所有符號內存引用被方法區(Method Area)的原始引用所替代。

1.3 初始化

這是類加載的最后階段,這里所有的靜態變量會被賦初始值, 并且靜態塊將被執行。

2. 運行時數據區(Runtime Data Area)

運行時數據區域被劃分為5個主要組件:

方法區(Method Area)?– 所有類級別數據將被存儲在這里,包括靜態變量。每個JVM只有一個方法區,它是一個共享的資源。

堆區(Heap Area)– 所有的對象和它們相應的實例變量以及數組將被存儲在這里。每個JVM同樣只有一個堆區。由于方法區和堆區的內存由多個線程共享,所以存儲的數據不是線程安全的。

棧區(Stack Area)– 對每個線程會單獨創建一個運行時棧。對每個函數呼叫會在棧內存生成一個棧幀(Stack Frame)。所有的局部變量將在棧內存中創建。棧區是線程安全的,因為它不是一個共享資源。棧幀被分為三個子實體:

1.局部變量數組– 包含多少個與方法相關的局部變量并且相應的值將被存儲在這里。

2.操作數棧– 如果需要執行任何中間操作,操作數棧作為運行時工作區去執行指令。

3.幀數據– 方法的所有符號都保存在這里。在任意異常的情況下,catch塊的信息將會被保存在幀數據里面。

4.PC寄存器– 每個線程都有一個單獨的PC寄存器來保存當前執行指令的地址,一旦該指令被執行,pc寄存器會被更新至下條指令的地址。

5.本地方法棧– 本地方法棧保存本地方法信息。對每一個線程,將創建一個單獨的本地方法棧。

3. 執行引擎

分配給運行時數據區的字節碼將由執行引擎執行。執行引擎讀取字節碼并逐段執行。

解釋器– 解釋器能快速的解釋字節碼,但執行卻很慢。 解釋器的缺點就是,當一個方法被調用多次,每次都需要重新解釋。

JIT 編譯器– JIT編譯器消除了解釋器的缺點。執行引擎利用解釋器轉換字節碼,但如果是重復的代碼則使用JIT編譯器將全部字節碼編譯成本機代碼。本機代碼將直接用于重復的方法調用,這提高了系統的性能。

1.中間代碼生成器– 生成中間代碼

2.代碼優化器– 負責優化上面生成的中間代碼

3.目標代碼生成器?– 負責生成機器代碼或本機代碼

4.探測器(Profiler)?– 一個特殊的組件,負責尋找被多次調用的方法。

3.垃圾回收器: 收集并刪除未引用的對象。可以通過調用"System.gc()"來觸發垃圾回收,但并不保證會確實進行垃圾回收。JVM的垃圾回收只收集哪些由new關鍵字創建的對象。所以,如果不是用new創建的對象,你可以使用finalize函數來執行清理。

如何才能成為一個公司的頂梁柱般架構師呢?

基本知識

1.學會分析源碼

程序員每天都和代碼打交道。經過數年的基礎教育和職業培訓,大部分程序員都會「寫」代碼,或者至少會抄代碼和改代碼。但是,會讀代碼的并不在多數,會讀代碼又真正讀懂一些大項目的源碼的,少之又少。這種怪狀,真要追究起來,怪不得程序員這個群體本身 —— 它是兩個原因造成的:

我們所有的教育和培訓都在強調怎么寫代碼,并沒有教大家如何讀代碼

大多數工作場景都是一個蘿卜一個坑,我們只需要了解一個系統的局部便能開展工作,讀不相干的代碼,似乎沒用

讀源碼三問:“為什么要有這樣的架構”,“他是什么樣子的”,“他是怎么工作的”。

那么阿里程序員是如何去讀代碼的呢?

2.分布式架構特點及設計理念

首先需要說明的是,分布式系統是一個復雜且寬泛的研究領域,學習一兩門在線課程,看一兩本書可能都是不能完全覆蓋其所有內容的。介于這篇文章是引導初學者入門,所以我個人覺得為初學者介紹一下當前分布式系統領域的全貌,也許比直接推薦論文和課程更有幫助。當初學者對這個領域建立起一個大的 Picture 之后,可以根據自己的興趣,有選擇性的深入不同領域進行進一步的學習。

3.為什么微服務會這么火?

要學習微服務,首先,我們要了解為什么使用微服務。

代碼難以理解?

構建和部署耗時長,難以定位問題,開發效率低?

單體只能按整體橫向擴展,無法分模塊垂直擴展?

一個bug有可能引起整個應用的崩潰?

受技術棧限制,團隊成員使用同一框架和語言?

那么如何解決單體的不足呢,通過遷移到微服務架構來解決,我們看一下什么是微服務。

微服務架構:將單體應用拆分為多個高內聚低耦合的小型服務,每個小服務運行在獨立進程,由不同的團隊開發和維護,服務間采用輕量級通信機制,獨立自動部署,可以采用不同的語言及存儲。

單體架構整個團隊維護開發一個大工程及一個單庫,到了微服務架構,用戶請求經過API Gateway被路由到下游服務,服務之間以輕量級通信協議進行通信,服務通過注冊中心發現彼此,每個服務都有專門的開發維護團隊,每個服務對應獨立的數據庫,服務獨立開發,獨立部署和上線。

接下來我們總結下微服務的優點。

易于開發與維護

微服務相對小,易于理解

啟動時間短,開發效率高

獨立部署

一個微服務的修改不需要協調其它服務

伸縮性強

每個服務都可以在橫向和縱向上擴展

每個服務都可按硬件資源的需求進行獨立擴容

與組織結構相匹配

微服務架構可以更好將架構和組織相匹配

每個團隊獨立負責某些服務,獲得更高的生產力

技術異構性

使用最適合該服務的技術

降低嘗試新技術的成本

下面就送上學習架構圖吧

如果你覺得想提升下自己,學習文章中的知識,在此推薦一個免費公開課的地方,可以加群:433540541,找群主獲取上課資格,這是免費的課程,找群主要的時候可以客氣一點。

4.程序員到底要不要學習JVM

總有人問這個東西好像用不上,于是要不要學這樣的問題。

然后又總有人擔心一直搬磚成天做些重復沒提升的東西。

如果你這輩子只甘心做一個平庸的Java碼農,那么你完全沒有必要去學習JVM相關的知識,學習JVM對于一個Java程序員的好處大概可以概括為下幾點:

1.你能夠明白為什么Java最早期被稱為解釋型語言,而后來為什么又被大家叫做解釋與編譯并存的語言(了解JVM中解釋器以及即時編譯器就可以回答這個問題);

2.你能夠理解動態編譯與靜態編譯的區別,以及動態編譯相對于靜態編譯到底有什么好處(JVM JIT);

3.你能夠利用一些工具,jmap, jvisualvm, jstat, jconsole等工具可以輔助你觀察Java應用在運行時堆的布局情況,由此你可以通過調整JVM相關參數提高Java應用的性能;

4.可以清楚知道Java程序是如何執行的;

5.可以明白為什么Java等高級語言具有可移植性強的特性。

其實這個問題相當于“為什么C/C++程序員需要學體系結構與編譯原理?”

話不多說,附上學習體系圖

5.被我們忽略掉的工程化專題

IT產業行業細分化已經不是一天兩天的事了。集成技術這件事并不可恥可笑,反而是另一種可貴的能力。并不是像一些人形容的那樣,好像批發幾個CPU,拿到華強北就能把自己的電腦改裝成超級計算機了。

那么,為什么我們常常會忽略掉工程化這件事的價值呢?主要的原因,或許是因為工程化這件事本身就離我們太遠。一個產業工程化的普遍性越高,說明這個產業發展的越成熟:產業鏈細分、分工細化、全球化的研發和生產這些高效的工作方式開始出現。而產業成熟也往往代表著寡頭化情況顯著。

在IT產業中,寡頭化出現代表著創業公司減少——沒人再去用聲勢浩大的發布會講故事、沒人再去宣傳自己拿了多少融資。

這一代中國人自小的教育不比歐美的STEAM,而是重學術、輕手藝。我們往往會為工科和產能過剩畫上等號。強大的資本和技術門檻為這些產業蒙上了一層神秘的面紗,讓普通人很難真正了解到其中技術和工藝的復雜程度,也就更難明白其中的價值。可正是因為中國的工程化能力,才讓我們有機會走到AI時代的第一梯隊,而不僅僅是靠學術研究能力。

另外一個原因,或許在于我們天生“叛逆心”。超級計算機、手機芯片等等技術門檻較高的產業,其背后往往是大企業和國資科研機構。當評判的對象是他們時,我們似乎更愿意相信狗血的商業故事和陰謀論:比如科研經費都被教授們吃吃喝喝啦;搞超級計算機就是放衛星其實美日根本不care啦;XX企業的技術都是從創業公司買來的除了會賺用戶的錢啥技術都沒有……

產生這種“叛逆心”的原因太深刻,我們能做到的,只有在這種“慣性思維”出現時先按住自己奔向鍵盤的手,轉表達欲為好奇心,完成自己了解的義務,再去行使自己批判的權利。

附上思維腦圖

6.沒有高并發經驗,想進大公司該怎么辦?

假如沒有靠譜的公司,接觸不到高并發的業務場景怎么辦?你永遠解決的是小問題,工作10年技術也未必提升多少。

很多程序員也經常找我說,沒有經驗就沒有靠譜的公司收,沒有靠譜的公司也就沒有經驗,我看了無數的書,自己做了無數的實驗拼命想找個靠譜公司去深入,但是感覺好難,簡直是個死循環

讀者群的朋友大家都比較關注高并發,原因很簡單,想去BAT這樣的大公司,你必須要有高并發的經驗。今天普及下高并發的知識,希望大家對高并發有一個正確的認識。

7.學習千遍,不如項目實戰成功一次

我們在學習過程中最容易犯的一個錯誤就是:看的多,動手的少。特別是對一些項目的整體開發,我們接觸的機會就更少了。

一次完整的開發,是最好的學習。它能讓你對整個開發流程有完整的認識,對知識也會有極大的鞏固。更重要的是,你將學會將理論知識用到實際開發中的方法。

所以無論項目大小,一定要動手去進行開發學習。

項目實戰相信很多程序員都多少會有的,可是我們這個還要學習什么呢?

那就要看你想不想成為一個架構師了,為什么98%的程序員工作10年,一輩子還只是一個開發者。程序員們都要想一想這個問題,我是不是需要提升了。

我認為,學習項目實戰最重要的還是學習項目管理,作為程序員,都應該學點項目管理。

凡事皆為“項目”

項目的兩類屬性(復雜的邏輯,龐大的信息量)

人腦擅長的是思考,而不是記憶

成為一個“獨當一面”的人

獨當一面是一個很性感的詞。是否擁有它,對應的職場價值,有著天壤之別的。

所有老板都喜歡“獨當一面”的員工,因為這是最省心力、最好算賬的模式:給你一塊資源,給你一個 title,給你一個目標,然后你給我打出一片天地來。

當你能獨立對一攤子事情負責,并把它們一一搞定,你會擁有大幅度的職場溢價——相應的,其收入回報,也遠非“技術螺絲”可比了。

如果你很進取,你會逐漸地:主導一個小組,一個部門,一個家庭,甚至還是城市……而這所有的一切起點,正是獨立完整地做好一個項目:你沒有誰可以依靠,你要對其中大大小小的事務負責,你要對最后的結果。

換句話說,“項目管理”是“獨當一面”的元能力。在這個過程中,你的意識越發清晰,你的方法論越發成熟,你的信心更加沛,項目越做越大。直到某天,你真的有了掌控一方的封疆大吏。

這就是我們學習“項目實戰”的終極意義。

或許作為程序員的你想提升自己,卻找不到突破口,公司沒人帶。又或許你已經工作6年了,卻還是很迷茫,很多知識都還是不懂,也沒有達到自己期望的一個職位,薪資。在此推薦一個免費公開課的地方,上面所提到的架構師基本知識點都有資料,可以加群:433540541,找群主獲取上課資格,這是免費的課程,找群主要的時候可以客氣一點。

到這里,你可能認為文章已經完了,學完這些就可以去BAT大公司做一個架構師,年薪50W+嗎?

不,你錯了,這些都知識最基本的知識,想要成為一個架構師必須是一個累積的過程,也是這么多程序員終其一生也只是一個開發,到年齡就會被公司辭退。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,116評論 25 708
  • 這篇文章是我之前翻閱了不少的書籍以及從網絡上收集的一些資料的整理,因此不免有一些不準確的地方,同時不同JDK版本的...
    高廣超閱讀 15,697評論 3 83
  • 很久沒有用彩鉛了,決定玩把大的,找了8開的素描紙。 同樣的,為了避免意外還是先畫線稿,不過你以為我會在8開的紙上就...
    四月青閱讀 892評論 8 20
  • 屋外的雨,淅淅瀝瀝。 父親的煙,繚繞卷手。 母親的奶茶,彌漫過喉。 你的笑容,純真無憂。 寂寞的靈魂, 開始長草,...
    墨白樂兮閱讀 123評論 1 2