關于什么是 JVM,看看普通?和??的回答。
普通人
JVM 就是 Java 虛擬機,是?來運?我們平時所寫的 Java 代碼的。優點是它會
?動進?內存管理和垃圾回收,缺點是?旦發?問題,要是不了解 JVM 的運?
機制, 就很難排查出問題所在。
高手
JVM 全稱是 Java 虛擬機,在聊什么是 JVM 之前,我們不妨看?下這張圖。
從這張圖中可以看出 JVM 所處的位置,同時也能看出它兩個作用:
l 運?并管理 Java 源碼?件所?成的 Class?件,
l 在不同的操作系統上安裝不同的 JVM,從?實現了跨平臺的保證。
?般情況下,對于開發者??,即使不熟悉 JVM 的運?機制并不影響業務代碼的開發,因為在安裝完 JDK 或者 JRE 之后,其中就已經內置了 JVM,所以只需要將 Class?件交給 JVM 運?即可。
但當程序運?的過程中出現了問題,?這個問題發生在 JVM 層?的,那我們就需要熟悉 JVM 的運?機制,才能迅速排查并解決 JVM 的性能問題。
我們先看下目前主流的 JVM HotSpot 的架構圖,通過這張架構圖,我們可以看出 JVM 的大致流程是把一個 class 文件通過類加載器加載進系統,然后放到不同的區域,通過編譯器編譯。
第一個部分 Class Files
在 Java 中,Class?件是由源碼?件?成的,?于源碼?件的內容,是每個 Java開發者在 JavaSE 階段的必備知識,這?就不再贅述了,我們可以關注?下 Class?件的格式,?如其中的常量池、成員變量、?法等,這樣就能知道 Java 源碼內容在 Class?件中的表示?式
第二個部分 Class Loader Subsystem 即類加載機制
Class?件加載到內存中,需要借助 Java 中的類加載機制。類加載機制分為裝載、鏈接和初始化,其主要就是對類進?查找、驗證以及分配相關的內存空間和賦值
第三個部分 Runtime Data Areas 也就是通常所說的運?時數據區
其解決的問題就是 Class?件進入內存之后,該如何進?存儲不同的數據以及數據該如何進?扭轉。比如:Method Area 通常會儲存由 Class?件常量池所對應的運?時常量池、字段和?法的元數據信息、類的模板信息等;Heap 是存儲各種 Java 中的對象實例;Java Threads 通過線程以棧的?式運?加載各個?法;Native Internal Thread 可以理解為是加載運?native 類型的?法;PC Register則是保存每個線程執??法的實時地址。
這樣通過運?時數據區的 5 個部分就能很好地把數據存儲和運?起來了
第四個部分 Garbage Collector 也就是通常所說的垃圾回收
就是對運?時數據區中的數據進?管理和回收。回收機制可以基于不同的垃圾收集器,?如 Serial、Parallel、CMS、G1、ZGC 等,可以針對不同的業務場景選擇不同的收集器,只需要通過 JVM 參數設置 即可。如果我們打開 hotspot 的源碼,可以發現這些收集器其實就是對于不同垃圾收集算法的實現,核?的算法有3 個:標記-清除、標記-整理、復制
-
標記-清除:標記-清除算法即先標記處待回收的垃圾對象,然后回收其內存區域。
這種算法存在兩個缺點:一是這回收過程中需要大量標記,清除動作。隨著堆中對象數量的增長,執行效率越來越低;二是會產生內存碎片,導致在分配大對象時有可能沒有連續的內存,提前觸發再一次垃圾回收。
-
標記-整理:標記-復制算法在對象存活率較高時,就要隨之進行更多的復制操作,效率也隨之降低。同時如果不想浪費一半的內存空間,就要提供上述的逃生門機制,需要有其他內存空間托底。因此這種算法并不適合對老年代進行回收。
標記-整理算法通常用來回收老年代,它的過程是這樣的:在發生老年代回收時,首先標記存活的對象,然后將存活對象向內存的一端移動,最后清理掉邊界以外的內存區域。
-
標記-復制:標記-復制算法即先將堆劃分為兩個區域,新建對象時只使用其中一個區域分配內存,發生 GC 時先標記存活的對象,然后將存活的對象復制到另一塊空間中,然后再清空之前的空間。
對象存活的數量較多時,需要做大量的復制操作,將會產生大量的空間復制開銷。但是在對象存活數量較少時,只需復制少量的對象,然后一次性清理之前使用的空間。在復制時只需按照順序分配另一塊的內存即可,不會產生內存碎片問題,算法簡單高效,標記-復制算法特別適合對于年輕代的垃圾回收。
這種算法最大的缺點顯而易見:分配對象時只使用了一半空間,有很嚴重的空間浪費。
針對這個問題,其實可以通過調整前后兩塊內存空間的占比來優化,具體的做法是:在 JVM 中,將堆的空間主要分為兩部分,年輕代和老年代,同時對于年輕代又劃分為 Eden 區域、From 區域和 To 區域。
新建的對象被分配到 Eden Space 中,當 Eden 區域空間滿時,就觸發一次 Young GC,已經不被使用的做回收處理,而仍然被使用的則被復制到 From 區域。經過這個過程,整個Eden區域就是空閑的,如果有新的對象,就 Eden 區域中創建。如果Eden區域的內存再次被用完,就再一次觸發了 Young GC ,這時就將 Eden 區域和 From 區域中還在使用的對象復制到 To 區域。下一次 Young GC 則是將 Eden 區域和 To 區域中還在使用的對象全部復制到 From 區域。
如此,經過多次 Young GC 后,會存在某些對象在 From 區域和 To 區域進行多次復制,如果超過某個閾值對象仍然沒有釋放,則將這些對象復制到 Old Generation。如果Old Generation 區域也用完之后,就會觸發 Full GC ,全量回收會對系統的性能造成非常大的影響,所以可以根據各應用的特點和對象的生命周期來設置一個合理的年輕代與老年代的大小值,盡量減少 Full GC。
在 HotSpot 虛擬機中,默認 Eden 和 Survivor(指其中的一塊) 的大小比例是 8 :1,即只浪費了 10 % 的空間。當 Survivor 的空間無法存儲仍在存活的對象時,會有類似逃生門的機制,直接進入老年代空間。
第五個部分是 JIT Compiler 和 Interpreter
通俗理解就是翻譯器,Class 的字節碼指令通過 JIT Compiler 和 Interpreter 翻譯成對應操作系統的 CPU 指令,只不過可以選擇解釋執?或者編譯執?,在HotSpot JVM 默認采用的是這兩種?式的混合。
第六就是 JNI 的技術
如果我們想要找 Java 中的某個 native?法是如何通過 C 或者 C++實現的,那么可以通過 Native Method Interface 來進?查找,也就是所謂的 JNI 技術。
通過官?上給出的 HotSpot 架構圖,我們就能夠知道 JVM 到底是如何運行的了,當然在實際操作的過程中我們可以借助?些 JVM 參數:
和?些常?的 JDK 常?命令
再結合 JDK 常??具以及第三?的?些?具
我們就可以優雅地分析 JVM 出現的常?問題并對其進?調優。
以上就是我對 JVM 的理解。
好的,看完高手的回答后,相信每位看完視頻的小伙伴對 JVM 有了更深刻的理解了。