每一個(gè)Java 開發(fā)人員都知道字節(jié)碼由JRE (Java運(yùn)行時(shí)環(huán)境)執(zhí)行。但許多人不知道JRE是Java虛擬機(jī)(JVM)的實(shí)現(xiàn), 它負(fù)責(zé)分析字節(jié)碼、解析并執(zhí)行代碼。作為一個(gè)開發(fā)人員了解JVM架構(gòu)是非常重要的,因?yàn)樗刮覀兡芨咝У木帉懘a。在這篇文章中我們將更深入了解Java中的JVM架構(gòu)以及JVM的各個(gè)組件。
JVM是什么?
虛擬機(jī) 是物理機(jī)器的一個(gè)軟件實(shí)現(xiàn)。Java運(yùn)行在VM上,實(shí)現(xiàn)WORA (一處編寫,處處運(yùn)行)。 編譯器將Java文件編譯成Java .class 文件,然后這個(gè).class文件被輸入到JVM中進(jìn)行類文件的加載和執(zhí)行。下面是一個(gè)JVM的架構(gòu)圖。
JVM是如何工作的呢?
正如上面的架構(gòu)圖所示,JVM被分為三個(gè)主要的子系統(tǒng):
類加載器子系統(tǒng)
運(yùn)行時(shí)數(shù)據(jù)區(qū)
執(zhí)行引擎
1. 類加載器子系統(tǒng)
Java的動(dòng)態(tài)類加載功能是由類加載器子系統(tǒng)處理。當(dāng)它在運(yùn)行時(shí)(不是編譯時(shí))首次引用一個(gè)類時(shí),它加載、鏈接并初始化該類文件。
1.1 加載
類由此組件加載。啟動(dòng)類加載器 (Boot Strap class Loader)、擴(kuò)展類加載器(Extension class Loader)和應(yīng)用程序類加載器(Application class Loader) 這三種類加載器幫助完成類的加載。
啟動(dòng)類加載器 – 負(fù)責(zé)從啟動(dòng)類路徑中加載類,無非就是rt.jar。這個(gè)加載器會(huì)被賦予最高優(yōu)先級(jí)。
擴(kuò)展類加載器 – 負(fù)責(zé)加載ext 目錄(jre\lib)內(nèi)的類.
應(yīng)用程序類加載器 – 負(fù)責(zé)加載應(yīng)用程序級(jí)別類路徑,涉及到路徑的環(huán)境變量等etc.
上述的類加載器會(huì)遵循委托層次算法(Delegation Hierarchy Algorithm)加載類文件。
1.2 鏈接
校驗(yàn) – 字節(jié)碼校驗(yàn)器會(huì)校驗(yàn)生成的字節(jié)碼是否正確,如果校驗(yàn)失敗,我們會(huì)得到校驗(yàn)錯(cuò)誤。
準(zhǔn)備 – 分配內(nèi)存并初始化默認(rèn)值給所有的靜態(tài)變量。
解析 – 所有符號(hào)內(nèi)存引用被方法區(qū)(Method Area)的原始引用所替代。
1.3 初始化
這是類加載的最后階段,這里所有的靜態(tài)變量會(huì)被賦初始值, 并且靜態(tài)塊將被執(zhí)行。
2. 運(yùn)行時(shí)數(shù)據(jù)區(qū)(Runtime Data Area)
運(yùn)行時(shí)數(shù)據(jù)區(qū)域被劃分為5個(gè)主要組件:
方法區(qū)(Method Area)?– 所有類級(jí)別數(shù)據(jù)將被存儲(chǔ)在這里,包括靜態(tài)變量。每個(gè)JVM只有一個(gè)方法區(qū),它是一個(gè)共享的資源。
堆區(qū)(Heap Area)– 所有的對(duì)象和它們相應(yīng)的實(shí)例變量以及數(shù)組將被存儲(chǔ)在這里。每個(gè)JVM同樣只有一個(gè)堆區(qū)。由于方法區(qū)和堆區(qū)的內(nèi)存由多個(gè)線程共享,所以存儲(chǔ)的數(shù)據(jù)不是線程安全的。
棧區(qū)(Stack Area)– 對(duì)每個(gè)線程會(huì)單獨(dú)創(chuàng)建一個(gè)運(yùn)行時(shí)棧。對(duì)每個(gè)函數(shù)呼叫會(huì)在棧內(nèi)存生成一個(gè)棧幀(Stack Frame)。所有的局部變量將在棧內(nèi)存中創(chuàng)建。棧區(qū)是線程安全的,因?yàn)樗皇且粋€(gè)共享資源。棧幀被分為三個(gè)子實(shí)體:
1.局部變量數(shù)組– 包含多少個(gè)與方法相關(guān)的局部變量并且相應(yīng)的值將被存儲(chǔ)在這里。
2.操作數(shù)棧– 如果需要執(zhí)行任何中間操作,操作數(shù)棧作為運(yùn)行時(shí)工作區(qū)去執(zhí)行指令。
3.幀數(shù)據(jù)– 方法的所有符號(hào)都保存在這里。在任意異常的情況下,catch塊的信息將會(huì)被保存在幀數(shù)據(jù)里面。
4.PC寄存器– 每個(gè)線程都有一個(gè)單獨(dú)的PC寄存器來保存當(dāng)前執(zhí)行指令的地址,一旦該指令被執(zhí)行,pc寄存器會(huì)被更新至下條指令的地址。
5.本地方法棧– 本地方法棧保存本地方法信息。對(duì)每一個(gè)線程,將創(chuàng)建一個(gè)單獨(dú)的本地方法棧。
3. 執(zhí)行引擎
分配給運(yùn)行時(shí)數(shù)據(jù)區(qū)的字節(jié)碼將由執(zhí)行引擎執(zhí)行。執(zhí)行引擎讀取字節(jié)碼并逐段執(zhí)行。
解釋器– 解釋器能快速的解釋字節(jié)碼,但執(zhí)行卻很慢。 解釋器的缺點(diǎn)就是,當(dāng)一個(gè)方法被調(diào)用多次,每次都需要重新解釋。
JIT 編譯器– JIT編譯器消除了解釋器的缺點(diǎn)。執(zhí)行引擎利用解釋器轉(zhuǎn)換字節(jié)碼,但如果是重復(fù)的代碼則使用JIT編譯器將全部字節(jié)碼編譯成本機(jī)代碼。本機(jī)代碼將直接用于重復(fù)的方法調(diào)用,這提高了系統(tǒng)的性能。
1.中間代碼生成器– 生成中間代碼
2.代碼優(yōu)化器– 負(fù)責(zé)優(yōu)化上面生成的中間代碼
3.目標(biāo)代碼生成器?– 負(fù)責(zé)生成機(jī)器代碼或本機(jī)代碼
4.探測(cè)器(Profiler)?– 一個(gè)特殊的組件,負(fù)責(zé)尋找被多次調(diào)用的方法。
3.垃圾回收器: 收集并刪除未引用的對(duì)象。可以通過調(diào)用"System.gc()"來觸發(fā)垃圾回收,但并不保證會(huì)確實(shí)進(jìn)行垃圾回收。JVM的垃圾回收只收集哪些由new關(guān)鍵字創(chuàng)建的對(duì)象。所以,如果不是用new創(chuàng)建的對(duì)象,你可以使用finalize函數(shù)來執(zhí)行清理。
如何才能成為一個(gè)公司的頂梁柱般架構(gòu)師呢?
基本知識(shí)
1.學(xué)會(huì)分析源碼
程序員每天都和代碼打交道。經(jīng)過數(shù)年的基礎(chǔ)教育和職業(yè)培訓(xùn),大部分程序員都會(huì)「寫」代碼,或者至少會(huì)抄代碼和改代碼。但是,會(huì)讀代碼的并不在多數(shù),會(huì)讀代碼又真正讀懂一些大項(xiàng)目的源碼的,少之又少。這種怪狀,真要追究起來,怪不得程序員這個(gè)群體本身 —— 它是兩個(gè)原因造成的:
我們所有的教育和培訓(xùn)都在強(qiáng)調(diào)怎么寫代碼,并沒有教大家如何讀代碼
大多數(shù)工作場(chǎng)景都是一個(gè)蘿卜一個(gè)坑,我們只需要了解一個(gè)系統(tǒng)的局部便能開展工作,讀不相干的代碼,似乎沒用
讀源碼三問:“為什么要有這樣的架構(gòu)”,“他是什么樣子的”,“他是怎么工作的”。
那么阿里程序員是如何去讀代碼的呢?
2.分布式架構(gòu)特點(diǎn)及設(shè)計(jì)理念
首先需要說明的是,分布式系統(tǒng)是一個(gè)復(fù)雜且寬泛的研究領(lǐng)域,學(xué)習(xí)一兩門在線課程,看一兩本書可能都是不能完全覆蓋其所有內(nèi)容的。介于這篇文章是引導(dǎo)初學(xué)者入門,所以我個(gè)人覺得為初學(xué)者介紹一下當(dāng)前分布式系統(tǒng)領(lǐng)域的全貌,也許比直接推薦論文和課程更有幫助。當(dāng)初學(xué)者對(duì)這個(gè)領(lǐng)域建立起一個(gè)大的 Picture 之后,可以根據(jù)自己的興趣,有選擇性的深入不同領(lǐng)域進(jìn)行進(jìn)一步的學(xué)習(xí)。
3.為什么微服務(wù)會(huì)這么火?
要學(xué)習(xí)微服務(wù),首先,我們要了解為什么使用微服務(wù)。
代碼難以理解?
構(gòu)建和部署耗時(shí)長(zhǎng),難以定位問題,開發(fā)效率低?
單體只能按整體橫向擴(kuò)展,無法分模塊垂直擴(kuò)展?
一個(gè)bug有可能引起整個(gè)應(yīng)用的崩潰?
受技術(shù)棧限制,團(tuán)隊(duì)成員使用同一框架和語言?
那么如何解決單體的不足呢,通過遷移到微服務(wù)架構(gòu)來解決,我們看一下什么是微服務(wù)。
微服務(wù)架構(gòu):將單體應(yīng)用拆分為多個(gè)高內(nèi)聚低耦合的小型服務(wù),每個(gè)小服務(wù)運(yùn)行在獨(dú)立進(jìn)程,由不同的團(tuán)隊(duì)開發(fā)和維護(hù),服務(wù)間采用輕量級(jí)通信機(jī)制,獨(dú)立自動(dòng)部署,可以采用不同的語言及存儲(chǔ)。
單體架構(gòu)整個(gè)團(tuán)隊(duì)維護(hù)開發(fā)一個(gè)大工程及一個(gè)單庫,到了微服務(wù)架構(gòu),用戶請(qǐng)求經(jīng)過API Gateway被路由到下游服務(wù),服務(wù)之間以輕量級(jí)通信協(xié)議進(jìn)行通信,服務(wù)通過注冊(cè)中心發(fā)現(xiàn)彼此,每個(gè)服務(wù)都有專門的開發(fā)維護(hù)團(tuán)隊(duì),每個(gè)服務(wù)對(duì)應(yīng)獨(dú)立的數(shù)據(jù)庫,服務(wù)獨(dú)立開發(fā),獨(dú)立部署和上線。
接下來我們總結(jié)下微服務(wù)的優(yōu)點(diǎn)。
易于開發(fā)與維護(hù)
微服務(wù)相對(duì)小,易于理解
啟動(dòng)時(shí)間短,開發(fā)效率高
獨(dú)立部署
一個(gè)微服務(wù)的修改不需要協(xié)調(diào)其它服務(wù)
伸縮性強(qiáng)
每個(gè)服務(wù)都可以在橫向和縱向上擴(kuò)展
每個(gè)服務(wù)都可按硬件資源的需求進(jìn)行獨(dú)立擴(kuò)容
與組織結(jié)構(gòu)相匹配
微服務(wù)架構(gòu)可以更好將架構(gòu)和組織相匹配
每個(gè)團(tuán)隊(duì)獨(dú)立負(fù)責(zé)某些服務(wù),獲得更高的生產(chǎn)力
技術(shù)異構(gòu)性
使用最適合該服務(wù)的技術(shù)
降低嘗試新技術(shù)的成本
下面就送上學(xué)習(xí)架構(gòu)圖吧
如果你覺得想提升下自己,學(xué)習(xí)文章中的知識(shí),在此推薦一個(gè)免費(fèi)公開課的地方,可以加群:433540541,找群主獲取上課資格,這是免費(fèi)的課程,找群主要的時(shí)候可以客氣一點(diǎn)。
4.程序員到底要不要學(xué)習(xí)JVM
總有人問這個(gè)東西好像用不上,于是要不要學(xué)這樣的問題。
然后又總有人擔(dān)心一直搬磚成天做些重復(fù)沒提升的東西。
如果你這輩子只甘心做一個(gè)平庸的Java碼農(nóng),那么你完全沒有必要去學(xué)習(xí)JVM相關(guān)的知識(shí),學(xué)習(xí)JVM對(duì)于一個(gè)Java程序員的好處大概可以概括為下幾點(diǎn):
1.你能夠明白為什么Java最早期被稱為解釋型語言,而后來為什么又被大家叫做解釋與編譯并存的語言(了解JVM中解釋器以及即時(shí)編譯器就可以回答這個(gè)問題);
2.你能夠理解動(dòng)態(tài)編譯與靜態(tài)編譯的區(qū)別,以及動(dòng)態(tài)編譯相對(duì)于靜態(tài)編譯到底有什么好處(JVM JIT);
3.你能夠利用一些工具,jmap, jvisualvm, jstat, jconsole等工具可以輔助你觀察Java應(yīng)用在運(yùn)行時(shí)堆的布局情況,由此你可以通過調(diào)整JVM相關(guān)參數(shù)提高Java應(yīng)用的性能;
4.可以清楚知道Java程序是如何執(zhí)行的;
5.可以明白為什么Java等高級(jí)語言具有可移植性強(qiáng)的特性。
其實(shí)這個(gè)問題相當(dāng)于“為什么C/C++程序員需要學(xué)體系結(jié)構(gòu)與編譯原理?”
話不多說,附上學(xué)習(xí)體系圖
5.被我們忽略掉的工程化專題
IT產(chǎn)業(yè)行業(yè)細(xì)分化已經(jīng)不是一天兩天的事了。集成技術(shù)這件事并不可恥可笑,反而是另一種可貴的能力。并不是像一些人形容的那樣,好像批發(fā)幾個(gè)CPU,拿到華強(qiáng)北就能把自己的電腦改裝成超級(jí)計(jì)算機(jī)了。
那么,為什么我們常常會(huì)忽略掉工程化這件事的價(jià)值呢?主要的原因,或許是因?yàn)楣こ袒@件事本身就離我們太遠(yuǎn)。一個(gè)產(chǎn)業(yè)工程化的普遍性越高,說明這個(gè)產(chǎn)業(yè)發(fā)展的越成熟:產(chǎn)業(yè)鏈細(xì)分、分工細(xì)化、全球化的研發(fā)和生產(chǎn)這些高效的工作方式開始出現(xiàn)。而產(chǎn)業(yè)成熟也往往代表著寡頭化情況顯著。
在IT產(chǎn)業(yè)中,寡頭化出現(xiàn)代表著創(chuàng)業(yè)公司減少——沒人再去用聲勢(shì)浩大的發(fā)布會(huì)講故事、沒人再去宣傳自己拿了多少融資。
這一代中國(guó)人自小的教育不比歐美的STEAM,而是重學(xué)術(shù)、輕手藝。我們往往會(huì)為工科和產(chǎn)能過剩畫上等號(hào)。強(qiáng)大的資本和技術(shù)門檻為這些產(chǎn)業(yè)蒙上了一層神秘的面紗,讓普通人很難真正了解到其中技術(shù)和工藝的復(fù)雜程度,也就更難明白其中的價(jià)值??烧且?yàn)橹袊?guó)的工程化能力,才讓我們有機(jī)會(huì)走到AI時(shí)代的第一梯隊(duì),而不僅僅是靠學(xué)術(shù)研究能力。
另外一個(gè)原因,或許在于我們天生“叛逆心”。超級(jí)計(jì)算機(jī)、手機(jī)芯片等等技術(shù)門檻較高的產(chǎn)業(yè),其背后往往是大企業(yè)和國(guó)資科研機(jī)構(gòu)。當(dāng)評(píng)判的對(duì)象是他們時(shí),我們似乎更愿意相信狗血的商業(yè)故事和陰謀論:比如科研經(jīng)費(fèi)都被教授們吃吃喝喝啦;搞超級(jí)計(jì)算機(jī)就是放衛(wèi)星其實(shí)美日根本不care啦;XX企業(yè)的技術(shù)都是從創(chuàng)業(yè)公司買來的除了會(huì)賺用戶的錢啥技術(shù)都沒有……
產(chǎn)生這種“叛逆心”的原因太深刻,我們能做到的,只有在這種“慣性思維”出現(xiàn)時(shí)先按住自己奔向鍵盤的手,轉(zhuǎn)表達(dá)欲為好奇心,完成自己了解的義務(wù),再去行使自己批判的權(quán)利。
附上思維腦圖
6.沒有高并發(fā)經(jīng)驗(yàn),想進(jìn)大公司該怎么辦?
假如沒有靠譜的公司,接觸不到高并發(fā)的業(yè)務(wù)場(chǎng)景怎么辦?你永遠(yuǎn)解決的是小問題,工作10年技術(shù)也未必提升多少。
很多程序員也經(jīng)常找我說,沒有經(jīng)驗(yàn)就沒有靠譜的公司收,沒有靠譜的公司也就沒有經(jīng)驗(yàn),我看了無數(shù)的書,自己做了無數(shù)的實(shí)驗(yàn)拼命想找個(gè)靠譜公司去深入,但是感覺好難,簡(jiǎn)直是個(gè)死循環(huán)
讀者群的朋友大家都比較關(guān)注高并發(fā),原因很簡(jiǎn)單,想去BAT這樣的大公司,你必須要有高并發(fā)的經(jīng)驗(yàn)。今天普及下高并發(fā)的知識(shí),希望大家對(duì)高并發(fā)有一個(gè)正確的認(rèn)識(shí)。
7.學(xué)習(xí)千遍,不如項(xiàng)目實(shí)戰(zhàn)成功一次
我們?cè)趯W(xué)習(xí)過程中最容易犯的一個(gè)錯(cuò)誤就是:看的多,動(dòng)手的少。特別是對(duì)一些項(xiàng)目的整體開發(fā),我們接觸的機(jī)會(huì)就更少了。
一次完整的開發(fā),是最好的學(xué)習(xí)。它能讓你對(duì)整個(gè)開發(fā)流程有完整的認(rèn)識(shí),對(duì)知識(shí)也會(huì)有極大的鞏固。更重要的是,你將學(xué)會(huì)將理論知識(shí)用到實(shí)際開發(fā)中的方法。
所以無論項(xiàng)目大小,一定要?jiǎng)邮秩ミM(jìn)行開發(fā)學(xué)習(xí)。
項(xiàng)目實(shí)戰(zhàn)相信很多程序員都多少會(huì)有的,可是我們這個(gè)還要學(xué)習(xí)什么呢?
那就要看你想不想成為一個(gè)架構(gòu)師了,為什么98%的程序員工作10年,一輩子還只是一個(gè)開發(fā)者。程序員們都要想一想這個(gè)問題,我是不是需要提升了。
我認(rèn)為,學(xué)習(xí)項(xiàng)目實(shí)戰(zhàn)最重要的還是學(xué)習(xí)項(xiàng)目管理,作為程序員,都應(yīng)該學(xué)點(diǎn)項(xiàng)目管理。
凡事皆為“項(xiàng)目”
項(xiàng)目的兩類屬性(復(fù)雜的邏輯,龐大的信息量)
人腦擅長(zhǎng)的是思考,而不是記憶
成為一個(gè)“獨(dú)當(dāng)一面”的人
獨(dú)當(dāng)一面是一個(gè)很性感的詞。是否擁有它,對(duì)應(yīng)的職場(chǎng)價(jià)值,有著天壤之別的。
所有老板都喜歡“獨(dú)當(dāng)一面”的員工,因?yàn)檫@是最省心力、最好算賬的模式:給你一塊資源,給你一個(gè) title,給你一個(gè)目標(biāo),然后你給我打出一片天地來。
當(dāng)你能獨(dú)立對(duì)一攤子事情負(fù)責(zé),并把它們一一搞定,你會(huì)擁有大幅度的職場(chǎng)溢價(jià)——相應(yīng)的,其收入回報(bào),也遠(yuǎn)非“技術(shù)螺絲”可比了。
如果你很進(jìn)取,你會(huì)逐漸地:主導(dǎo)一個(gè)小組,一個(gè)部門,一個(gè)家庭,甚至還是城市……而這所有的一切起點(diǎn),正是獨(dú)立完整地做好一個(gè)項(xiàng)目:你沒有誰可以依靠,你要對(duì)其中大大小小的事務(wù)負(fù)責(zé),你要對(duì)最后的結(jié)果。
換句話說,“項(xiàng)目管理”是“獨(dú)當(dāng)一面”的元能力。在這個(gè)過程中,你的意識(shí)越發(fā)清晰,你的方法論越發(fā)成熟,你的信心更加沛,項(xiàng)目越做越大。直到某天,你真的有了掌控一方的封疆大吏。
這就是我們學(xué)習(xí)“項(xiàng)目實(shí)戰(zhàn)”的終極意義。
或許作為程序員的你想提升自己,卻找不到突破口,公司沒人帶。又或許你已經(jīng)工作6年了,卻還是很迷茫,很多知識(shí)都還是不懂,也沒有達(dá)到自己期望的一個(gè)職位,薪資。在此推薦一個(gè)免費(fèi)公開課的地方,上面所提到的架構(gòu)師基本知識(shí)點(diǎn)都有資料,可以加群:433540541,找群主獲取上課資格,這是免費(fèi)的課程,找群主要的時(shí)候可以客氣一點(diǎn)。
到這里,你可能認(rèn)為文章已經(jīng)完了,學(xué)完這些就可以去BAT大公司做一個(gè)架構(gòu)師,年薪50W+嗎?
不,你錯(cuò)了,這些都知識(shí)最基本的知識(shí),想要成為一個(gè)架構(gòu)師必須是一個(gè)累積的過程,也是這么多程序員終其一生也只是一個(gè)開發(fā),到年齡就會(huì)被公司辭退。