回覆列表
  • 1 # 程式猿W

    5年經驗,應該瞭解JVM常用的知識,下面說一下JVM有哪些知識點:

    JVM整體架構JVM記憶體管理java執行時資料區堆(執行緒共享)

    虛擬機器啟動時 建立,用於存放物件例項,幾乎所有的物件(包括常量池)都在堆上分配記憶體,當 物件無法再該空間申請到內部時將丟擲 OutOfMemoryError 異常。同時也是垃圾收集器管理的主要區域。可透過 -Xmx _xms引數來分別指定最大堆和最小堆。

    新生區:

    類誕生、成長、消亡的區域,一個類在這裡產生,應用,最後被垃圾回收器收集。

    伊甸區(Eden space):所有的類都在該區域new 出來的,當伊甸區的空間用完時,程式又需要建立物件,JVM垃圾回收器將對伊甸區進行垃圾回收(Minor GC),將伊甸園去中的不再 被其他物件所引用的物件進行銷燬。然後將伊甸園中的剩餘物件移動到倖存0區。若倖存0區滿了,再對該區進行垃圾回收,然後移動到1區。那如果1區也滿了呢??

    倖存者區(Survivor space):0區,1區

    老年區:

    新生區經過多次GC仍然存回的物件移動到老年區。若老年區也滿了,那麼這個時候將產生 MajorGC(FullGC),進行老年區的記憶體清理 ,若老年區執行了Full GC 之後發現仍然無法進行物件的儲存,就會產生OOM異常"OutOfMemoryError“。

    如果一個例項物件在新生代 中,成功的在15次垃圾回收之後,就會移動到老年代中

    2. java 棧(執行緒私有)

    一個執行緒對應一個棧,每個方法在執行的同時都會建立一個棧幀(使用者儲存區域性變量表,運算元棧,動態連結,方法出口等資訊),不存在垃圾回收問題,只要執行緒一結束該棧就釋放,生命週期和執行緒一致。

    該區域規範了兩種異常:

    執行緒請求的棧深度大於虛擬機器棧所允許的深度,並丟擲StackOverFlowError異常

    若虛擬機器棧可動態擴充套件,當無法申請到足夠記憶體空間時將丟擲OutOfMemoryError,透過JVM 引數 -Xss指定棧空間,空間大小決定函式呼叫的深度

    3. 方法區(執行緒共享)

    類的所有欄位和方法位元組碼,以及一些特殊方法如建構函式,介面程式碼也在此定義。簡單的說,所有定義的方法的資訊都儲存在該區域,靜態變數 + 常量 + 類資訊(構造方法/介面定義) + 執行時常量池都存在方法區中。

    4.元資料區

    元資料區取代了永久代(jdk1.8之前).本質和永久代相似,都是對JVM規範中方法區的實現,區別在於元資料區 不再虛擬機器彙總,而是使用本地物理記憶體,永久代在虛擬機器中,永久代邏輯結構上屬於堆,但是物理上不屬於堆,堆大小 = 新生代 + 老年代。 元資料區有可能發生OutOfMemory 異常

    jdk6 以及之前:有永久代,常量池在方法區

    jdk7 ,有永久代,常量池在堆上

    jdk8之後,無永久代,常量池在元空間

    元資料區的動態擴充套件,預設–XX:MetaspaceSize值為21MB的高水位線。一旦觸及則Full GC將被觸發並解除安裝沒有用的類(類對應的類載入器不再存活),然後高水位線將會重置。新的高水位線的值取決於GC後釋放的元空間。如果釋放的空間少,這個高水位線則上升。如果釋放空間過多,則高水位線下降。

    5、程式計數器(執行緒私有)

    記錄當前執行的位元組碼指令的位置,也就是記錄目前執行到了那一條位元組碼指令

    6、本地方法棧(執行緒私有)

    新生代和老年代的物件分配機制

    物件優先在eden分配

    大物件直接進入老年代:字串,陣列,虛擬機器提供了一個-XX:PretenureSizeThreshold引數,令大於這個設定的物件直接在老年代分配。這樣做的目的是避免在Eden區以及兩個Survivor區直接放生大量的記憶體複製

    長期存活的物件將進入老年代

    動態物件年齡判斷機制:為了更好的適應不同程式的記憶體情況,虛擬機器並不是永遠要求物件的年齡必需達到某個固定的值(比如前面說的 15)才會被晉升到老年代,而是會去動態的判斷物件年齡。如果在 Survivor 區中相同年齡所有物件大小的總和大於 Survivor 空間的一半,年齡大於等於該年齡的物件就可以直接進入老年代。

    空間擔保機制

    在發生Minor GC 之前,虛擬機器會先檢查老年代最大可用的連續空間是否大於新生代所有物件的總空間,如果成立,那麼Minor GC 可以確保是安全的。如果不成立,則虛擬機器會檢視HandlerPromotionFailure設定值是否允許擔保失敗》如果允許,就是看看老年代的記憶體大小,是否大於之前每一次Minor GC後進入老年代的物件的平均大小。如果上面的步驟判斷失敗了,或者是-XX:-HandlerPromotionFailuer引數沒設定,此時就會直接出發一次 FULL GC,就是對老年代進行垃圾回收,儘量騰出來一些記憶體空間,然後再執行Minor GC如果上面都判斷成功了。此時進行Minor GC 有幾種可能Minor GC 過後,剩餘的存活物件的大小,是小於Survivor區的大小的,那麼此時存活物件進入Survivor區域即可Minor GC過後,剩餘的存活物件的大小,是大於Survivor區域的代銷,但是小於老年代可用記憶體大小的,此時是直接進入來年代即可。Minor GC 過後,剩餘的存活物件的,大於了Survivor區域的大小,也大於了老年代可用記憶體的大小。此時老年代都放不下這些存活的物件,就會發生"Handle Promotion Failure" 的情況,這個時候就會觸發一次 Full GCJVM記憶體相關的集合核心引數

    -Xms:java堆記憶體的大小:通常情況下 -Xms 和 -Xmx 設定一樣

    -Xmx: java堆記憶體的最大大小

    -Xmn: Java堆記憶體中的新生代大小,扣除新生代剩下的就是老年代的記憶體大小

    -XX:PermSize: 永久代大小

    -XX:MaxPermSize: 永久代最大大小

    -XX:MetaspaceSize

    -XX:MaxMetaspaceSize

    -Xss: 每個執行緒的棧記憶體大小

    物件分配流程物件訪問方式虛擬機器類載入機制

    什麼時候會把

    .class

    位元組碼檔案載入到虛擬機器中?

    JVM對class檔案是按需載入(執行期間動態載入),非一次性載入,見示例(啟動需要加上引數:-verbose:class)

    類載入時機

    遇到new、getstatic、putstati 或 invokestatic 這4條指令時,如果類沒有進行初始化,則需要先觸發其初始化。生成者4條指令的java程式碼場景是: 使用new關鍵字例項化物件的時候、讀取或者設定一個類的靜態欄位(被final修飾、已在 編譯期把結果 放入常量池的靜態欄位除外)的時候,以及呼叫一個類的靜態方法的時候;使用java.lang.reflect 包的方法對類的進行反射呼叫的時候,如果類沒有進行過初始化,則需要先觸發其初始化。當初始化一個類的時候,如果沒有發現其父類還沒有進行過初始化,則需要先觸發其父類的初始化當虛擬機器啟動時,使用者需要指定一個要執行的主類(包含main()方法那個類),虛擬機器會先初始化這個主類

    3.類載入過程

    4.類與類載入器 : 類載入器 + 類 = 唯一

    5.雙親委派機制

    垃圾回收

    如何判斷物件為垃圾物件

    引用計算法在物件中新增一個引用計數器,當有地方引用這個物件的時候,計數器 + 1,當失效的時候,計數器 - 1 可達性分析法

    透過一些列的的稱為"GC Root" 的物件作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鏈。當一個物件到GCRoots 沒有任何引用鏈 相連時,則證明此 物件時不可用的

    可做為GC Roors的物件:虛擬機器棧(棧幀的本地變量表)中的引用物件,方法區中類靜態屬性的引用的物件,方法區中常量 引用的物件,本地方法棧中JNI引用的物件,

    一句話總結: 只要你的物件被方法的區域性變數、類的靜態變數給引用了,就不會回收他們。

    2.垃圾回收演算法

    標記清除

    複製

    標記整理

    分代演算法

    3.垃圾回收器

    Serial 和 Serial Old 垃圾回收器

    分別回收新生代和老年代的垃圾物件。

    工作原理: 垃圾回收的時候會停止我們自己寫的系統的其他工作執行緒,讓我們 系統直接卡死不動,然後讓他們垃圾 回收,這個現在一般寫後臺 java 系統幾乎不用。

    ParNew 和 CMS 垃圾回收器

    多執行緒回收垃圾

    執行緒數量: 預設和CPU的核數一樣

    CMS 是用在老年代的垃圾 回收器

    CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。它而非常符合在注重使用者體驗的應用上使用,它是HotSpot虛擬機器第一款真正意義上的併發收集器,它第一次實現了讓垃圾收集執行緒與使用者執行緒(基本上)同時工作。初始標記: 標記出來所有GC Roots直接引用的物件併發標記:在執行期間可能會建立新的存活物件,也可能讓部分存活物件失去引用,變成垃圾物件。在併發標記的時候,系統程式會不停的工作,他可能會各種創建出來新的物件,部分物件可能變成垃圾。需要對GC Roots進行深度追蹤,因為老年代裡存活的物件比較多。重新標記:在第二個階段,一遍標記存活物件和垃圾物件,一邊系統不停執行建立新物件,讓老物件變成垃圾。所以在第二階段結束之後,會有很多存活物件和垃圾物件,是之前沒有標記出來的併發清除:併發清理。需要把垃圾物件從各種隨機的記憶體位置清理掉,也是比較耗時的

    G1垃圾回收器

    統一收集新生代和老年代,採用了更加優秀的演算法和設計機制

    G1 (Garbage-First)是一款面向伺服器的垃圾收集器,主要針對配備多顆處理器及大容量記憶體的機器. 以極高機率滿足GC停頓時間要求的同時,還具備高吞吐量效能特徵.

    特點 :Java堆記憶體分為多個大小相等的Region。設定一個垃圾回收的預期停頓時間

    監控工具與故障處理工具

    命令列 工具

    jpsjstatjinfojmapjhatjstackhsdis

    2. jdk的視覺化工具

    jconsole

    visualvm

    Arthas:java診斷工具Btrace:故障分析工具GC日誌和執行緒

    GC日誌:gceasy

    堆疊定位:fastthread

  • 2 # IT人劉俊明

    對於應用級程式設計師來說,即使從事多年Java開發也不一定會涉及到虛擬機器的知識。這主要是由工作性質決定的。所以,有5年工作經驗的程式設計師,對於java虛擬機器機制並不十分了解也是比較正常的情況。

    對於應用級程式設計師來說,Java虛擬機器的作用就是一個實現Java功能的“容器”,程式設計師平時雖然每天都會接觸到虛擬機器,但是虛擬機器本身對程式設計師來說是“透明的”。大部分應用級程式設計師都是在容器之上從事功能性開發,也就是說透過Java API來完成大部分程式設計任務。簡單的說容器的作用就是“Don"t Call me,I"ll Call you”,可以理解為“在需要的時候會出現”。

    對於研發級程式設計師來說,掌握Java虛擬機器的機制是十分有必要的,因為研發級程式設計師往往都是以產品為導向,效能是研發級程式設計師關注的核心問題之一。Java虛擬機器是Java實現功能的基礎,提供了Java API的支援。Java虛擬機器考慮的核心問題有兩點,一點是功能的實現如何組織(Java位元組碼、方法呼叫原理等),另一點是最佳化(常量池、棧幀、執行引擎、生命週期管理等)。

    其實,即使是Java應用級程式設計師,瞭解Java虛擬機器的內部機制還是有一定必要的,因為在編寫程式碼的時候可以更好的運用Java虛擬機器的機制來提高程式碼的執行效率。瞭解Java虛擬機器能夠從更高的層次來了解Java語言,對程式語言也會有一個更深層次的認知。

  • 3 # 會點程式碼的大叔

    JVM,大部分程式設計師可能幾乎用不到,但這項技能是面試高階程式設計師的敲門磚,如果已經有五年的Java的開發經驗,對JVM還不甚瞭解,是可以理解的,因為可能一直關注業務功能開發,不過強烈建議還是補習JVM相關的知識。

    積累了一定的工作經驗之後,建議大家不要滿足單純的實現業務需求,要花一些時間關注程式的效能。也就是不僅讓程式“能跑”,還要讓程式跑的快;這也就是我們常說的“調優”;而JVM的調優是程式調優重要的一部分;只有深入學習JVM底層原理,才能做到知其然知其所以然。

    然而很多人程式設計師都覺得JVM是很高深的知識,我覺得主要是因為很多資料都是講概念,太生澀不好理解,還沒入門就放棄了,要知道每項技術的出現都是有背景的,理論結合著實踐,理解起來應該不會特別困難。

    學習虛擬機器,建議大概參考這個流程:

    Java記憶體模型:執行時候的資料區域,每個區域的作用,線上程的角度看待堆和棧;虛擬機器對物件的分配過程,訪問定位;堆引數的設定等等。

    垃圾回收相關:概念,GC演算法,記憶體分配及回收策略,記憶體洩露和記憶體溢位。

    JVM類載入相關:Class檔案,類載入的過程,類載入器

    JVM最佳化:常用的效能指標(響應時間、併發數、吞吐量),常用的最佳化手段。

    放對JVM有一定了解了之後,有一些問題再返回來看,就會容易很多,例如:

    不建立不必要的物件

    介面優於抽象類

    區域性變數的作用於最小化

    使類和成員的可訪問性最小化

    字串連線的效能

  • 4 # 此生唯一

    五年經驗不懂jvm,絕對面不上bat,甚至TMD這一類一線網際網路大廠!

    三年以上經驗的時候,不管去哪家公司面試,總會問關於jvm的東西,其實現在jvm預設配置都已經很強大了,而且在工作中實在用的很少,但終歸還是要學的,我就來回憶下,到底哪些jvm相關知識容易問到!

    1,jvm記憶體結構(堆疊等各種結構分割槽)與記憶體模型(多執行緒不安全的原因)的區別,具體的含義?

    2,有哪些垃圾收集演算法?複製演算法,標記清除,標記整理等等!

    3,新生代,老年代,永久代物件怎麼劃分?什麼時候處於什麼代?什麼時候回收?

    4,怎麼手動回收垃圾?1,重寫falinize方法並呼叫,2,呼叫system.gc,然後等待jvm回收,也即是說永遠不可能手動回收垃圾!

    5,怎麼判斷物件是否能回收?遍歷gc roots不可達的物件,就是可以回收的物件!

    引用計數法為什麼不能用來做為可回收物件依據?有些相互引用的物件永遠不會回收!

    6,垃圾收集器有哪些?有什麼區別?比較常用的CMS,G1收集器,以最大吞吐量,最小響應時間,儘量少的full gc等因素進行選擇!

    7,類載入的執行過程是什麼?雙親委派是啥意思?自行百度。。

    8,jvm監控工具?調優工具?調優引數?

    基本上掌握這些之後,jvm的相關面試都可以對答如流了,這也是網際網路大廠肯定會問的東西!

    誰讓現在的面試箴言就是,我們可以不用,但是你必須要會呢?jvm這也是我經常分享的東西,更多的技術分享,敬請關注。。

  • 5 # 高階Bug調查員

    看到這個問題,忍不住來湊湊熱鬧。(* ̄︶ ̄)

    我轉過頭,輕輕撫摸著案頭的《深入理解Java虛擬機器》,嘴角微微上揚——

    還記得那個夏天,面試官丟擲了幾個關於垃圾回收的問題。

    我略加思索,腦海中那個熟悉的畫面漸漸清晰——GC同學正在努力的完成著它的工作,忽然它停下手頭的工作,和我對視片刻。。。

    我總是習慣性的將Java的記憶體比作一個巨大的工廠,GC同學就是這個工廠的垃圾回收工,而每一個物件都有條有理的擺放在不同的區域,這都要歸功於GC同學的勤勞能幹。

    為了記住這些區域,我還給他們編了一條順口溜:

    兩棧(Java虛擬機器棧和本地方法棧)一計數(程式計數器),一堆(Java堆)一方法(方法區)。

    那些日子,我在那個密不透風的出租屋裡,像書蟲一樣蠶食著這本厚厚的《深入理解Java虛擬機器》,期待著能夠有朝一日亮瞎別人的雙眼——“天哪,你對JVM的理解真是太到位了!”“天哪,JVM調優你都可以擺平!真有你的!”

    思緒回到面試官的問題上,我淡定地回答了關於JVM的一切問題。

    思緒再一次回到現在,看了看這個題目,工作了5年對JVM知之甚少?我覺得這沒什麼不正常的。

    Java開發領域是非常廣泛的,Java語言的設計者遮蔽了有關底層編譯的相關工作,當然,還有物件的回收等工作。可以負責任地說,如今不太瞭解JVM相關知識的開發者不會低於50%。就算是工作10年的老鳥,可能也未必將JVM說得頭頭是道,更別提上手進行JVM調優。

    實際上,JVM相關知識在整個Java學習技術棧中,更像是和資料結構與演算法等理論性較強的知識一個等級。平時很少會用到。

    然而,如果稍微上進一點的程式設計師,都不會忽視這一塊的學習。

    我們應當保持一種寬容進取的態度,主動學習,但也不能嘲笑和批評他人的短板。

    因為我個人對JVM也只是停留在書本層面的膚淺理解,所以我也就不過多評價他人的種種了。

  • 6 # 極客宇文氏

    對於一個5年工作經驗的Java程式設計師,不懂jvm,也就是傳說中的Java虛擬機器,這是非常正常的事情。

    Java這一行學問很多,可以細分非常多的方向,每個人側重都有差異。有的人對資料庫調優非常有造詣,那他可能就沒有過多關注虛擬機器。有的人對架構很有想法,那他關注點更多的是結合業務和技術選型,不懂jvm也屬於正常。你能說他們不懂jvm他們技術水平不高嗎,那自然不能下這個結論。

    jvm在許多面試時都會問到,或深或淺,甚至現在的校招生都會遇到這類問題。所謂面試造火箭,乾貨擰螺絲,實際上在工作中jvm幾乎是用不到的,即使是高階工程師都很少專研這方面。

    因此不要因為jvm而有過多執念,但是瞭解一點jvm對Java的瞭解會有更加底層的深挖。

  • 7 # 老顧聊技術

    這個很正常,因為jvm一般工作用不到,當然你要成為高手,一定要去了解jvm知識,尤其寫底層框架,中介軟體的,是一定需要了解的。

    當然你不要恐慌,知道jvm的技術人員,也就是個皮毛,什麼新生代,老年代等。整體應用絕大數也是不懂的。在一線大廠面試的時候,肯定會問到jvm;但真正工作就會少點,除了你分配到架構部等寫底層元件的部門。別人說的好:面試的時候要你造火車,工作的時候扭螺絲。

  • 8 # JDIt

    怎麼說那,java只是一個工具,jvm是核心。你可以不能憑腦力記住所有的配置項,但是需要明白他的架構,運作原理,大體有那些配置,有那些問題及大體的處理方案。最後可以憑藉這個知識結構,遇到調優需要去翻閱資料或者筆記。

    目前工作不再是單一要求了,可能做一個產品一個開發人員至少需要js,html5,css3,java,mongo,mysql,oracle,redis,python,kafka,activemq,nginx,openresty,lua,c,shell,bat再加上開發框架等等。

    現在開發人員要求越來越高,從前端寫到伺服器程序,sql最佳化,表設計,linux或者windows伺服器問題處理,伺服器端自動化指令碼開發和除錯,以及高併發處理,都是又開發人員做,做不到就會被釋放。

  • 9 # LarryLe

    開車10年的人也不一定了解發動機原理,也不一定知道汽油機和柴油機有啥不同。但完全不耽誤人家開車世界跑。你用了windows 20多年了吧,知道作業系統原理麼?我覺著java無非就是個工具,會用,能做出符合客戶需求的好產品才是關鍵。多在需求上下功夫,多在如何用好這個工具上下功夫,比如設計模式,程式碼複用,過程控制,哪一樣上都值得花時間啊。底層原理知道再多能幹嘛,你又不是開發java的。無非跟孔乙己一樣,多知道茴的幾種寫法而已,毛用沒有。

  • 10 # 使用者9260054420388

    JVM知之甚少,究其原因用的不多,非架構師級別

    我們在工作當中很多時候都是處理業務需求,碼程式碼,很少會去涉及到底層JVM的知識,但是作為多年開發經驗的java工程師還是有必要了解,這樣有幫助我們寫出更加優美的程式碼。

    基本大廠面試都會問,主要是看你對JAVA底層的理解

    更高效,更有質量的程式碼一般都會考慮到JVM的原理來設計,JVM的知識買書來學習,推薦《深入java虛擬機器》

    五年經驗知道的少很正常,而且絕大部分人也一樣

    不止5年,10年的java經驗的人也有對jvm不瞭解的,當然這種情況的人也擔任不了架構師。目前jvm的配置基本已經滿足需求使用,除非高併發需求比較大的,需要特殊jvm調優。

  • 11 # 小蔡帶你看科技

    這個問題得從多個角度去考慮了。

    首先,是需求度的問題。現在的程式設計師大多數都是用到什麼學習什麼,經常開發業務如OA系統那種業務,系統訪問量不是很大,JVM調優的用武之地非常小,基本上用不到。所以也就沒有必要費時間去學習JVM了。

    其次,還得看程式設計師本身,一個只是餬口而不是真正熱愛程式設計的人來說,精益求精是不存在的,更不用說利用下班時間去學習技術了。

    最後我想說的是,一個工作5年的java程式設計師,很有可能五年在傳統軟體行業一直做業務。這類程式設計師工作都是穩定的,想從一個地方養老,工作的年限多了混個小頭兒很知足。

    希望越來越多的程式設計師大神積極分享技術,將中國程式設計領域推到一個新的高度,追趕上像美國這樣的技術大國。感謝!

  • 12 # 千鋒長沙

    有5年Java經驗的人,對於JVM知之甚少這很不正常,隨著網際網路的發展,高併發高可用、快速響應成為軟體的必須,而JVM與這些有著密切關聯。之前JVM系列好多都是一些由於STW影響到快速響應問題,忽然網站慢一下(抖動下)等問題,下面談談最近透過JVM排查到的高併發高可用問題。(在高可用高併發下面問題原因可能會很多,比如cpu異常高、磁碟IO高、SWAP空間等,有可能很多問題都是綜合性的問題)

    以前在我的認知裡面,如果服務執行有問題,最簡單有效快速地辦法就是重啟,最近遇到了問題打破了我對該方法的認知。

    某業務線最近叢集服務升級忽然上線上去不能提供服務,之後影響到整個叢集,檢視當時伺服器情況,負載、cpu、io、swap等都正常,檢視日誌就是卡在最後一行不動了(也沒有發現OOM,等任何異常)。

    如果是之前估計這個問題我也就排查不了了,現在排查問題多了一個維度JVM(的確有時候需要考慮的,並且現在很多監控工具都會考慮到JVM的),檢視gcutil檢視比例,發現from 100% eden 100% old 100%但是服務就是沒有OOM,執行任何都命令都非常緩慢了(更別談訪問請求了),檢視具體gc日誌發現concurrent mode failure 並且時間很長,猜測就是一瞬間量把記憶體給用完了,導致from 100% eden 100% old 100%現象,最終不能提供服務,之後其他叢集節點也陸續出現了此類情況,重啟無效,現象一樣很快就from 100% eden 100% old 100% 不能提供服務,沒辦法,一直重啟直到都啟動好了可以正常提供服務。

    留了一臺進行排查問題,執行jmap -histo pid無果,加-F也無果,後來執行jmap -dump:format=b,file=heap.bin pid (6G堆執行了3-4個小時左右)透過MAT分析檢視,發現都是某個邏輯產生的資料,佔用了5G左右(char[]、String、Map、List等都與某個邏輯程式碼有關)猜測是該問題(由於涉及到公司具體業務不方便截圖,只能大概說明下),很容易定位到程式碼最後是由於併發沒有考慮好,邏輯寫的也有點問題導致的,進行修改處理,問題解決,出了JVM相關問題可以進行排查解決。

    很能很多人認為線上出現問題可以排查繼續解決問題的人牛逼,其實錯了,真正牛逼的人都是在問題產生前就解決了(需要意識裡面轉變和學習思考提高的地方)。

    下面看個例子就明白了,是Charles告訴我的,我覺得放在這裡特別合適:

    春秋戰國時期,有位神醫被尊為“醫祖”,他就是“扁鵲”。一次,魏文王問扁鵲說:“你們家兄弟三人,都精於醫術,到底哪一位最好呢?”扁鵲答:“長兄最好,中兄次之,我最差。”文王又問:“那麼為什麼你最出名呢?”扁鵲答:“長兄治病,是治病於病情發作之前,由於一般人不知道他事先能剷除病因,所以他的名氣無法傳出去;中兄治病,是治病於病情初起時,一般人以為他只能治輕微的小病,所以他的名氣只及本鄉里;而我是治病於病情嚴重之時,一般人都看到我在經脈上穿針管放血,在面板上敷藥等大手術,所以以為我的醫術高明,名氣因此響遍全國。”

    如果能在編碼時候就考慮到JVM,做到面向JVM程式設計那就更牛逼了,如果能在上線前查閱到此類JVM問題或者是OOM問題以及一些其他問題那也就好了。

    綜述:因此這些成為必不可少的技能,所以面試需要了解,因為公司可能會面臨該問題。

    供大於求

    現在不像以前了,以前會點html都好找工作,現在由於學習軟體的人越來越多,而且每年大學生都在畢業(而老一輩的也很少換工作)人只會越來越多,有個笑話,隨便在大街上扔硬幣砸到的那個可能就是搞軟體的,現在人員太多,公司為了區分,會多新增維度,每多一個維度可能就會刷掉一批人,核心供大於求,所以我們也必須朝著這些大的方向努力,使得自己的競爭力比別人強。

    面試風氣

    簡單的問題都不好意思問,怕面試者鄙視面試公司問的問題。現在有一股妖風,不管啥公司都慢慢像阿里這樣的公司靠近,面試不問點jvm、併發、分散式都不好意(雖然公司可能沒有用到,雖然可能僅僅CURD),老是覺得問問這些顯得逼格高點,不管處於什麼原因很多公司的確都在學習他們,都在問這些問題,那麼我們就朝著這些大的方向努力也是沒錯的,如果朝著這些方向努力就是他們需要的人才,那麼也就對了。

  • 13 # Seven的程式碼實驗室

    這個其實也很正常,其實很多程式設計師在工作中用到JVM效能調優的情況很少,可以說大部分情況用不到,但用不掉是不是意味著可以不用學習了呢?個人認為還是很有必要學習的,學習JVM其實就像你學習古詩詞一樣,你說學習古詩詞有什麼用?至少能提高你的審美以及文化水平吧,那麼瞭解JVM,起碼能讓你更加了解底層程式碼的執行原理,提高對技術的認知水平,而且你在簡歷上加上了解JVM效能調優,那麼你的簡歷就跟別人區分開來了。

    以下是我綜合整理的JVM基礎知識,希望看完能讓你對JVM基礎知識有更深的理解。

    JVM如何載入class

    載入階段(Loading)、連線階段(Linking)、初始化階段(Initializing)

    載入階段(Loading)

    載入階段主要做3件事情:

    透過類全限定名獲取定義此類的二進位制位元組流;將位元組流代表的靜態儲存結構轉換為方法區的執行時資料結構;在記憶體中生成此類的java.lang.Class物件,作為方法區這個類的各種資料的訪問入口。

    連線階段(Linking)

    Linking的過程分為三小步:

    Verification是校驗裝進來的class檔案是不是符合class檔案的標準,假如你裝進來的不是這個CA FE BA BE,在這個步驟就被拒絕掉了。Preparation是把class檔案靜態變數賦預設值,不是賦初始值,比如你static i = 8 ,注意這個步驟8並不是把i值賦成8,而是先賦0。Resolution是把class檔案常量池裡面用到的符號引用轉換為直接記憶體地址,可以直接訪問到的內容。

    初始化階段(Initializing)

    Initlalizing意思是把靜態變數賦初始值。

    雙親委派機制

    雙親委派是一個孩子向父親方向,然後父親向孩子方向的雙親委派過程。

    一個class檔案需要被load記憶體的時候是這樣的

    任何一個class,假如你定義了ClassLoader,這時候就先嚐試去自定義的ClassLoader裡面找,他內部維護著快取,先問你有沒有幫我把這個class載入進來了?如果載入進來了就不需要載入第二遍了,如果沒有載入進來,那就趕緊把我載入進來。

    他如果在自定義的ClassLoader快取中沒有找到的話,他並不是直接載入這個類,他會先去他的父親Application父載入器,說爸爸你有沒有把這個類載入進來了呀?這個時候Application也會去他的快取裡面找有沒有這個類,如果有則返回,如果沒有則委託給他的父親Bootstrap,同理Bootstrap也會去他的快取中找看有沒有這個類,有則返回,沒有則繼續委託給他的父親Extendsion去載入,這時候Extendsion說我只負責載入擴充套件jar包裡的類,你的類我找不到,麻煩Application去載入,Application又說我只是負責載入classpath路徑下的類,其他的我也找不到,然後再委託給自定義的ClassLoader去載入。

    整個過程經過了一圈轉了一圈,才真正把這個類載入進來,當我們能夠把這個類載入進來的時候叫做成功,如果載入不進來,丟擲異常ClassNotfoundException。

    這就叫雙親委派

    CPU的記憶體結構以及Java Memory Model

    CPU計算核心與記憶體之間有三級快取,快取離CPU計算核心越遠容量越大、速度越慢,反之則容量越小、速度越快。

    CPU計算核心與記憶體之間存在著三級快取,那麼這個時候就會帶來資料一致性的問題,如果在單執行緒的環境資料一致性是沒有問題的,但是在多執行緒環境中就很難保證資料的一致性了。為了解決這個問題,CPU引入了一個數據一致性的協議,這個協議叫MESI

    關於MESI協議更詳細的描述,大家可以檢視這篇文章【併發程式設計】MESI--CPU快取一致性協議

    Java的記憶體模型(Java Memory Model)其實就是仿照CPU的記憶體結構來設計和定義的。

    JMM是一種規範,目的是解決由於多執行緒透過共享記憶體進行通訊時,存在的本地記憶體資料不一致、編譯器會對程式碼指令重排序、處理器會對程式碼亂序執行等帶來的問題。

    Java記憶體模型中規定了所有的變數都儲存在主記憶體中,每個執行緒有自己的工作記憶體(類比快取理解),執行緒的工作記憶體中儲存了該執行緒使用到主記憶體中的變數複製,執行緒對變數的所有操作(讀取、賦值)都必須在工作記憶體中進行,而不能直接讀寫主記憶體中的變數。不同執行緒之間無法直接訪問對方工作記憶體中的變數,執行緒間變數值的傳遞(通訊)均需要在主記憶體來完成。

    Java物件的記憶體佈局

    在 HotSpot虛擬機器中,物件在記憶體中的儲存佈局分為三塊區域:

    物件頭(Header)

    例項資料(Instance Data)

    對齊填充(Padding)

    一個java物件在記憶體中佔多少個位元組呢?

    64位系統(未開啟指標壓縮):Mark Word佔用8個位元組 + Class Pointer佔用8個位元組 = 16個位元組 (16已經是8的整數倍,所以不需要對齊填充)

    物件頭的大小:16個位元組

    64位系統(開啟指標壓縮):Mark Word 佔用8個位元組 + Class Pointer 佔用4個位元組 + 對齊填充 4個位元組 = 16個位元組 (空物件,所以例項資料大小為0)

    物件頭的大小:12個位元組

    以上就是關於JVM的部分基礎知識

    程式碼實驗室的建立已經有一段時間了,建立本號的初衷是為了做技術的分享,透過系統的整理JVM的基礎知識讓大家更加了解Java底層的執行邏輯,要知其然,更要知其所以然。

  • 中秋節和大豐收的關聯?
  • 草木灰水溶液能直接用施肥槍打葡萄根系附近嗎?