JVM基礎(chǔ)知識筆記

參考鏈接:https://juejin.im/post/5b45ef49f265da0f5140489c

JVM是否會一次性加載所有類?

image.png

三種默認(rèn)的類加載器及其工作職責(zé)?

image.png

雙親委派模型是什么?

image.png

JIT即時編譯器是什么?

【JIT編譯器詳解】https://www.ibm.com/developerworks/cn/java/j-lo-just-in-time/

Java字節(jié)碼重新編譯優(yōu)化,生成機器碼,讓CPU直接執(zhí)行,一般對熱點代碼做編譯,非熱點代碼直接解析就好了。

怎么區(qū)別是否是熱點代碼呢?通過“采樣”和“計數(shù)器”,HotSpot使用的是計數(shù)器的方法:“方法調(diào)用計數(shù)器”和“回編計數(shù)器”,在確定虛擬機運行參數(shù)的前提下,這兩個計數(shù)器都有一個確定的閾值,當(dāng)計數(shù)器超過閾值溢出了,就會觸發(fā)JIT編譯。

image.png

1) 為什么引入JIT即時編譯器?

java通過 javac 將程序源代碼編譯,轉(zhuǎn)換成 java 字節(jié)碼,JVM 通過解釋字節(jié)碼將其翻譯成對應(yīng)的機器指令,逐條讀入,逐條解釋翻譯。很顯然,經(jīng)過解釋執(zhí)行,其執(zhí)行速度必然會比可執(zhí)行的二進制字節(jié)碼程序慢很多。為了提高執(zhí)行速度,引入了 JIT 技術(shù)。

2) 寄存器優(yōu)化

寄存器的使用是編譯器的一個非常普遍的優(yōu)化。對一個變量多次進行操作,如果頻繁的從主存中獲取值,會帶來很大的開銷。編譯器加載一個寄存器給 sum 并賦予其初始值,利用寄存器里的值來執(zhí)行操作,并將最終的結(jié)果從寄存器返回給主存。

3) JIT編譯的兩種模式

客戶端模式和服務(wù)器模式:可以再運行時選擇其中一種編譯模式,-server 模式啟動時,速度較慢,但是一旦運行起來后,性能將會有很大的提升。當(dāng)虛擬機運行在-client 模式的時候,使用的是一個代號為 C1 的輕量級編譯器,而-server 模式啟動的虛擬機采用相對重量級代號為 C2 的編譯器。C2 比 C1 編譯器編譯的相對徹底,服務(wù)起來之后,性能更高。

4)優(yōu)化代碼緩存

JVM 編譯代碼時,它會將匯編指令集保存在代碼緩存。代碼緩存具有固定的大小,并且一旦它被填滿,JVM 則不能再編譯更多的代碼。沒有一個好的機制可以確定一個特定的應(yīng)用到底需要多大的代碼緩存,通常的做法是將代碼緩存變成默認(rèn)大小的兩倍或四倍。代碼緩存的初始大小是基于芯片架構(gòu)(例如 Intel 系列機器,client 編譯器模式下代碼緩存大小起始于 160KB,server 編譯器模式下代碼緩存大小則起始于 2496KB)以及使用的編譯器的。重定義代碼緩存的大小并不會真正影響性能,所以設(shè)置 ReservedCodeCacheSize 的大小一般是必要的。

5)編譯閾值

JVM 編譯代碼編譯是基于兩個計數(shù)器:一個是方法被調(diào)用的次數(shù),另一個是方法中循環(huán)被回彈執(zhí)行的次數(shù)?;貜椏梢杂行У谋徽J(rèn)為是循環(huán)被執(zhí)行完成的次數(shù),不僅因為它是循環(huán)的結(jié)尾,也可能是因為它執(zhí)行到了一個分支語句。檢查這兩個計數(shù)器的總和以決定這個方法是否有資格被編譯。如果方法里有一個很長的循環(huán)或者是一個永遠(yuǎn)都不會退出并提供了所有邏輯的程序會怎么樣呢?這種情況下,JVM 需要編譯循環(huán)而并不等待方法被調(diào)用。所以每執(zhí)行完一次循環(huán),分支計數(shù)器都會自增和自檢。如果分支計數(shù)器計數(shù)超出其自身閾值,那么這個循環(huán)(并不是整個方法)將具有被編譯資格。這種編譯叫做棧上替換(OSR),因為即使循環(huán)被編譯了,這也是不夠的:JVM 必須有能力當(dāng)循環(huán)正在運行時,開始執(zhí)行此循環(huán)已被編譯的版本。換句話說,當(dāng)循環(huán)的代碼被編譯完成,若 JVM 替換了代碼(前棧),那么循環(huán)的下個迭代執(zhí)行最新的被編譯版本則會更加快。

標(biāo)準(zhǔn)編譯是被-XX:CompileThreshold=Nflag 的值所觸發(fā)。Client 編譯器模式下,N 默認(rèn)的值 1500,而 Server 編譯器模式下,N 默認(rèn)的值則是 10000。 client 編譯器和 server 編譯器在最終的性能上有很大的差別,很大程度上是因為編譯器在編譯一個特定的方法時,對于兩種編譯器可用的信息并不一樣。降低編譯閾值,尤其是對于 server 編譯器,承擔(dān)著不能使應(yīng)用程序運行達(dá)到最佳性能的風(fēng)險,但是經(jīng)過測試應(yīng)用程序我們也發(fā)現(xiàn),將閾值從 8000 變成 10000,其實有著非常小的區(qū)別和影響。

一個方法擁有編譯資格之后,會將其放入隊列排隊等待編譯,編譯并不會遵守先進先出的原則,而是哪一個方法的計數(shù)器高,哪一個方法首先進行編譯。

5)調(diào)優(yōu)手段

從優(yōu)化的角度講,最簡單的選擇就是使用 server 編譯器的分層編譯技術(shù),這將解決大約 90%左右的與編譯器直接相關(guān)的性能問題。最后,請保證代碼緩存的大小設(shè)置的足夠大,這樣編譯器將會提供最高的編譯性能。

JVM內(nèi)存模型?

image.png
  • 堆:存放對象實例,幾乎所有的對象實例都在這里分配內(nèi)存
  • 虛擬機棧:虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法被執(zhí)行的時候都會同時創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表、操作棧、動態(tài)鏈接、方法出口等信息
  • 本地方法棧:本地方法棧則是為虛擬機使用到的Native方法服務(wù)。
  • 方法區(qū):用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)
  • 程序計數(shù)器:當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器

GC垃圾回收?

引用計數(shù)法(存在循環(huán)引用的問題)和可達(dá)性算法(主流的JVM采用的是這種方式)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡(luò)上收集的一些資料的整理,因此不免有一些不準(zhǔn)確的地方,同時不同JDK版本的...
    高廣超閱讀 16,051評論 3 83
  • 一、為什么要學(xué)習(xí)JVM Java采用了自動的內(nèi)存管理方式,程序員實際上不用關(guān)心內(nèi)存管理的細(xì)節(jié),那為什么我們?nèi)匀恍枰?..
    嗷大彬彬閱讀 1,190評論 0 1
  • 從三月份找實習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍(lán)閱讀 42,797評論 11 349
  • jvm原理 Java虛擬機是整個java平臺的基石,是java技術(shù)實現(xiàn)硬件無關(guān)和操作系統(tǒng)無關(guān)的關(guān)鍵環(huán)節(jié),是java...
    AI喬治閱讀 17,560評論 21 486
  • 網(wǎng)址:http://www.iashes.com/2015-01-403.html 詳細(xì)內(nèi)容請見網(wǎng)址(第三方刷新內(nèi)...
    iOS小菜鳥閱讀 393評論 0 2

友情鏈接更多精彩內(nèi)容