溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

關(guān)于JVM的基礎(chǔ)知識有什么呢

發(fā)布時間:2022-01-11 14:34:53 來源:億速云 閱讀:137 作者:柒染 欄目:編程語言

這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)關(guān)于JVM的基礎(chǔ)知識有什么呢,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

虛擬機(jī)給人的感覺像是操作系統(tǒng)、編譯器:非常高大上。但是Java程序就跑在上面,遇到問題還得去排查,性能不行還得去優(yōu)化,基礎(chǔ)的知識還是需要的!

內(nèi)存管理

Java虛擬機(jī)在執(zhí)行的過程中會把它所管理的內(nèi)存劃分為若干個不同的數(shù)據(jù)區(qū)域,大致如下:

關(guān)于JVM的基礎(chǔ)知識有什么呢

各部分的功能如下:

關(guān)于JVM的基礎(chǔ)知識有什么呢

在內(nèi)存管理部分比較大的一塊內(nèi)容是GC(垃圾回收),所謂垃圾回收就是將垃圾占用的內(nèi)存回收掉。那么第一個問題:什么是垃圾?

  • 引用計(jì)數(shù)算法:被引用次數(shù)為0的對象。

  • 根搜索算法:從GC Roots沿著引用找不到的對象。

這里都提到了引用,在JDK 1.2之后Java就已經(jīng)對引用的概念進(jìn)行了擴(kuò)充,那么第二個問題:有哪些類型的引用?

  • 強(qiáng)引用:Object o = new Object()這種都是強(qiáng)引用。

  • 弱引用:還有用但非必須的,在OOM之前被回收。

  • 軟引用:更弱的引用,在下次GC的時候被回收。

  • 虛引用:最弱的,唯一的作用是在對象被回收的時候可以收到通知。

這里只有強(qiáng)引用才能對對象的生命周期造成影響。在虛擬機(jī)發(fā)展的過程中進(jìn)化出不少垃圾回收算法,比如:

  • 標(biāo)記-清除算法

  • 復(fù)制算法

  • 標(biāo)記-整理算法

  • 分代收集算法

在實(shí)際中用到的回收器都是這幾種算法的組合,比如從VisualVM中看到的內(nèi)存是這樣的(需要明白各部分都是怎樣互相配合的):

關(guān)于JVM的基礎(chǔ)知識有什么呢

整體上來看是分代收集算法,而S0、S1這兩部分可以看做是標(biāo)記-整理算法。那么第三個問題:常見的CMS垃圾回收器的執(zhí)行流程是怎樣的?

  • 初始標(biāo)記:GC Roots直接關(guān)聯(lián)的對象。

  • 并發(fā)標(biāo)記:Root Tracing。

  • 重新標(biāo)記:修復(fù)由于程序運(yùn)行導(dǎo)致標(biāo)記產(chǎn)生變動。

  • 并發(fā)清除

具體如下圖所示:

關(guān)于JVM的基礎(chǔ)知識有什么呢

可以看到只有在初始標(biāo)記和重新標(biāo)記的時候才需要Stop The World,其他都是和用戶線程一起執(zhí)行,不要以為這就完美了,并行執(zhí)行的過程會消耗掉一些CPU資源。

代碼執(zhí)行

把Java源碼丟給JVM肯定是不能執(zhí)行的,需要先用javac編譯成class文件才行,那么第一個問題:class文件的結(jié)構(gòu)是怎樣的?

  • 常量池

  • 訪問標(biāo)志

  • 類索引、父類索引和接口索引

  • 字段表

  • 方法表

  • 屬性表

虛擬機(jī)規(guī)范并沒有規(guī)定在什么時候要加載類,但是規(guī)定了在遇到new、反射、父類、Main的時候需要初始化完成。整個類的生命周期如下:

關(guān)于JVM的基礎(chǔ)知識有什么呢

在虛擬機(jī)中通過ClassLoader來進(jìn)行類的加載,這地方需要明白:

  • 兩個類是否相同,除了類名外還需要判斷ClassLoader是否相同。

  • 雙親委派模式并不是一個強(qiáng)制約束。

在類加載完成之后就可以開始執(zhí)行了,和線程運(yùn)轉(zhuǎn)相關(guān)的東西都放在棧幀中,其結(jié)構(gòu)如下:

關(guān)于JVM的基礎(chǔ)知識有什么呢

執(zhí)行中具體調(diào)用哪個方法是個頭疼的問題,需要處理:

  • 靜態(tài)分派:相同名稱、不同參數(shù)類型的方法。

  • 動態(tài)分派:繼承中復(fù)寫的方法。

字節(jié)碼中的指令都是基于棧的操作,比如要完成1+1這樣的計(jì)算,對應(yīng)的指令如下:

iconst_1 // 將常量1壓入棧iconst_1iadd // 把棧頂?shù)膬蓚€值相加并出棧,然后把結(jié)果放回棧istore_0 // 將棧頂?shù)闹捣诺骄植孔兞勘淼?個Solt

解釋執(zhí)行的好處是下載后啟動速度快,但是確定也非常明顯:運(yùn)行速度慢。JIT正是用來解決這個問題的,能夠?qū)⒍啻握{(diào)用的方法、多次執(zhí)行的循環(huán)體編譯成本地代碼。

優(yōu)化是個很好玩的題目,記得在參加一次變成比賽的時候用gcc -O3編譯之后的代碼把printf()都沒輸出了。。在JIT中比較常見的優(yōu)化手段有:

關(guān)于JVM的基礎(chǔ)知識有什么呢

程序執(zhí)行一定會涉及到內(nèi)存操作,在Java中定義了八種操作來完成:

關(guān)于JVM的基礎(chǔ)知識有什么呢

這里有必要講一下volatile的作用,在使用到的時候能明白下面兩條即可:

  • 保證變量對所有線程是可見的。

  • 禁止指令重排優(yōu)化。

如果Java中所有的操作都需要程序員來控制的話,會有大量的重復(fù)代碼,而且寫起來很累,那么我們可以通過先行發(fā)生原則來判斷并行的兩個操作是否存在沖突:

  • 程序次序規(guī)則:單線程內(nèi)按照程序書寫順序。

  • 管程鎖定規(guī)則:unlock必須在lock之前。

  • volatile變量規(guī)則:寫操作先行發(fā)生于讀操作。

  • 線程啟動規(guī)則:Thread.start()先于線程的其他任意方法。

  • 線程終止規(guī)則:線程中所有的操作都先于對此線程的終止檢測。

  • 線程中斷規(guī)則:interrupt()先于中斷檢測。

  • 對象終結(jié)規(guī)則:對象的初始化完成先于它的finalize()方法。

  • 傳遞規(guī)則:如果A先于B、B先于C,那么A先于C。

Thread的底層實(shí)現(xiàn)還是比較麻煩的,但是最起碼應(yīng)該知道Thread的狀態(tài)是如何進(jìn)行轉(zhuǎn)換:

關(guān)于JVM的基礎(chǔ)知識有什么呢

最后,常見的同步方式是synchronized或者aqs的各種實(shí)現(xiàn)。

上述就是小編為大家分享的關(guān)于JVM的基礎(chǔ)知識有什么呢了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

jvm
AI