您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關怎樣理解HotSpot JVM的基本原理,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
Java?編程語言是一種通用的、并發的、面向對象的語言。它的語法類似于C和C++,但它省略了許多使C和C++復雜、混亂和不安全的特性。
Java 是幾乎所有類型的網絡應用程序的基礎,也是開發和提供嵌入式和移動應用程序、游戲、基于 Web 的內容和企業軟件的全球標準。.
從筆記本電腦到數據中心,從游戲控制臺到科學超級計算機,從手機到互聯網,Java 無處不在!
Java的技術體系主要有各種硬件平臺上的JVM虛擬機、提供各開發領域接口支持的Java API、Java編程語言、三方Java框架(Spring等)構成。
Java程序設計語言、Java虛擬機、Java API類庫這三部分統稱為JDK(Java Development Kit),JDK是用于支持Java程序開發的最小環境。
可以把Java API類庫中的Java SE API子集和Java虛擬機這兩部分統稱為JRE(Java Runtime Environment),JRE是支持Java程序運行的標準環境。
下圖展示了Java技術體系所包含的內容,以及JDK和JRE所涵蓋的范圍。
Java虛擬機是Java平臺的基石。負責其硬件和操作系統的獨立性,為Java字節碼的執行提供運行時環境。
JVM虛擬機在Java 虛擬機規范中沒有規定具體實現,而是有各大廠商自己實現。
Implementation details that are not part of the Java Virtual Machine's specification would unnecessarily constrain the creativity of implementors. For example, the memory layout of run-time data areas, the garbage-collection algorithm used, and any internal optimization of the Java Virtual Machine instructions (for example, translating them into machine code) are left to the discretion of the implementor.
Classic VM 是“世界上第一款商用Java虛擬機”,在JDK 1.2之前是Sun JDK中唯一的虛擬機。
在JDK 1.2時,它與HotSpot VM并存,而在JDK 1.3時,HotSpot VM成為默認虛擬機,直到JDK 1.4的時候,Classic VM才完全退出商用虛擬機的歷史舞臺。
1999年4月27日,HotSpot虛擬機發布,HotSpot最初由一家名為“Longview Technologies”的小公司開發,因為HotSpot的優異表現,這家公司在1997年被Sun公司收購了。后來它成為了JDK 1.3及之后所有版本的Sun JDK的默認虛擬機。
在2008年和2009年,Oracle公司分別收購了BEA公司和Sun公司,這樣Oracle就同時擁有了兩款優秀的Java虛擬機:JRockit VM和HotSpot VM。
Java HotSpot虛擬機是Sun用于Java平臺的VM。 它使用許多先進技術為Java應用程序提供最佳性能,包括最先進的內存模型,垃圾收集器和自適應優化器。
在SUN/Orace JDK中包括兩種風格的VM
client mode
server mode
默認以client mode
啟動。
啟動命令加- server
,以server mode
啟動。
查看當前JVM mode:
兩種mode的區別:
client mode
短時間內啟動,運行時,占用更少內存
C1輕量級編譯器,優化較少
適合輕量級程序和桌面程序
server mode
啟動慢,運行時,占用更大的內存
C2重量級編譯器,更徹底的優化
能提供更好的性能,適合生產部署
HotSpot JVM Architecture
HotSpot JVM 主要包括3個組件:
Class Loader Subsystem
Runtime Data Areas
Execution Engine
Class Loader Subsystem
是JVM必不可少的核心,用于讀取/加載.class
文件,并把字節碼保存在JVM方法區。
Java虛擬機中類加載的全過程:加載,驗證,準備,解析,初始化。
Loading
階段,虛擬機完成三件事情:
通過一個類的全限定名來獲取定義此類的二進制字節流;
將這個字節流所代表的靜態存儲結構轉換為方法區的運行時數據結構;
在內存中生成一個代表這個類的java.lang.class
對象,作為方法區這個類的各種數據的訪問入口。
加載的第一步是在Java虛擬機外部去實現的,有‘類加載器’來完成加載動作。
絕大部分Java程序都會用到以下3種系統提供的類加載器:
啟動類加載器(Bootstrap ClassLoader)
使用C++語言實現,是虛擬機自身的一部分。
加載<JAVA_HOME>/lib中虛擬機識別的jar,如rt.jar。
無法被Java程序直接引用
擴展類加載器(Extension ClassLoader)
由sun.misc.Launcher$ExtClassLoader實現
加載<JAVA_HOME>/lib/ext中類庫
Java程序可以直接使用
應用程序類加載器(Application ClassLoader)
由sun.misc.Launcher$AppClassLoader實現
也稱系統類加載器,加載應用程序classpath下的jar
可以直接使用,程序中默認的類加載器
執行類或接口的鏈接。
Verification,驗證。確保Class文件的字節流中包含的信息符合當前虛擬機的要求,且不會危害虛擬機的安全。
Preparation,準備。在方法區中為類變量(被static修飾的變量)分配內存并設置初始值。
Resolution,解析。虛擬機將常量池的符號引用替換為直接引用。
執行類加載的最后階段,為所有靜態變量都分配了原始值,靜態塊從父類執行到子類。
Delegation,委派
Visibility,可見性
Uniqueness,唯一性
雙親委派模型
雙親委派模型在JDK1.2中被引入,要求除了啟動類加載器,其他類加載器都要有父類加載器。
加載過程:當一個類加載器收到加載請求的時候,先委派給父類加載器去完成,每個層次的類加載器都是如此,最終加載請求傳到頂層啟動類加載器。如果父類無法完成加載請求,子類才會去嘗試加載。
破壞雙親委派模型
雙親委派解決了各類加載器的基礎類的統一問題。
如果基礎類需要反調用戶代碼,怎么辦?
線程上下問類加載器(Thread Context ClassLoader),TCCL。解決基礎類反調用戶代碼。例如JDK中實現SPI機制的JDBC、JNDI等。
子類加載器能看到父類加載器加載的類。父類加載器看不到子類加載器中的類。
父類加載器加載過的類不會被子類加載器加載。
Runtime Data Areas
大致可以分為兩部分:
線程私有區,線程創建時分配內存。線程啟動時初始化,并在線程完成后銷毀,
線程共享區,所有線程都可以訪問。JVM啟動時初始化,在關閉時銷毀。
保存當前正在執行的JVM指令地址。每個線程都有自己的PC。
每個Java虛擬機線程都有一個私有Java虛擬機堆棧,與線程同時創建。
供用非Java語言實現的本地方法的堆棧。換句話說,它是用來調用通過JNI(Java Native Interface Java本地接口)調用的C/C++代碼。根據具體的語言,一個C堆棧或者C++堆棧會被創建。
用來保存實例或者對象的空間,而且它是垃圾回收的主要目標。當討論類似于JVM性能之類的問題時,它經常會被提及。JVM提供者可以決定怎么來配置堆空間,以及不對它進行垃圾回收。
方法區是所有線程共享的,它是在JVM啟動的時候創建的。它保存所有被JVM加載的類和接口的運行時常量池,成員變量以及方法的信息,靜態變量以及方法的字節碼。JVM的提供者可以通過不同的方式來實現方法區。在Oracle 的HotSpot JVM里,方法區被稱為永久區或者永久代(PermGen)。是否對方法區進行垃圾回收對JVM的實現是可選的。
JDK1.8以后,PermGen被永久移除,有Metaspace(元空間)來實現方法區。
與永久代之間最大的區別在于:元空間并不在虛擬機中,而是使用本地內存。
因此,默認情況下,元空間的大小僅受本地內存限制
這個區域和class文件里的constant_pool是相對應的。這個區域是包含在方法區里的,不過,對于JVM的操作而言,它是一個核心的角色。因此在JVM規范里特別提到了它的重要性。除了包含每個類和接口的常量,它也包含了所有方法和變量的引用。簡而言之,當一個方法或者變量被引用時,JVM通過運行時常量區來查找方法或者變量在內存里的實際地址。
讀取字節碼指令并以順序方式執行。
JIT (Just In Time) Compiler。
抵消了Interpreter執行速度慢的缺點并提高了性能。 JIT編譯器同時編譯字節碼的類似部分,從而減少了編譯所需的總時間。
通過收集和刪除未引用的對象來釋放內存。
在堆里面存放著Java世界幾乎所有的對象實例,垃圾收集器在對堆進行回收前,第一件事就是要判斷對象是否存活。
引用計數算法(Reference Counting)實現簡單,判定效率也很高。給對象中添加一個引用計數器,每當一個地方引用它時,計數器值就加1;引用失效時,計數器值就減1;計數器為0的對象就是不可能再被使用的。
Python語言、游戲腳本領域被廣泛應用的Squire中都使用了引用計數算法進行內存管理。但是,java虛擬機里沒有用,主要原因是很難解決對象之間相互循環引用的問題
可達性分析(Reachability Analysis),基本思路是通過一系列的稱為“GC Roots”的對象作為起始點,從這些節點開始往下搜索,搜索所走過的路程稱為引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象不可用。
Java語言中,可作為GC Roots的對象包括以下幾種:
虛擬機棧(棧幀中的本地變量表)中引用的對象;
方法區中類靜態屬性引用的對象
方法區中常量引用的對象
本地方法棧中JNI(Native方法)引用的對象
常見的垃圾收集算法。
算法分為‘標記’、‘清除’兩個階段。
首先標記出所有需要回收的對象,在標記完成后統一回收所有被標記的對象。
復制(Copying),將可用內存按容量分為大小相等的兩塊,每次只使用其中的一塊。 當這一塊的內存用完了,將還存活的對象復制到另外一塊上去。把已使用過的內存空間一次清理掉。
實現簡單,運行高效,內存使用率不高,用于回收新生代。
IBM研究表明,新生代中98%的對象都是在第一次GC時被回收掉,不需要按照1:1分配空間。
HotSpot虛擬機默認Eden和Survivor比例是8:1,只有10%的內存會被浪費。
Survivor空間不夠時,需要依賴老年代進行分配擔保,新生代收集下來的存活對象直接進入老年代。
標記-整理(Mark-Compact)算法,標記所有存活對象,向一端移動,然后直接清理掉端邊界意外的內存。
根據對象存活周期不同,將Java堆分為新生代和老年代。
新生代,采用復制算法。
老年代采用‘標記-清理’或者‘標記-整理’算法。
如果說,收集算法是內存回收的方法論,那么,垃圾收集器就是內存回收的具體體現。
Java虛擬機規范沒有規范如何實現垃圾收集器。不同的廠商、版本的虛擬機實現可能會有很大差別。
下面,基于JDK1.7 Update14之后的HotSpot虛擬機討論收集器。
"Serial" is a stop-the-world, copying collector which uses a single GC thread.
"ParNew" is a stop-the-world, copying collector which uses multiple GC threads.
"Parallel Scavenge" is a stop-the-world, copying collector which uses multiple GC threads.
"Serial Old" is a stop-the-world, mark-sweep-compact collector that uses a single GC thread.
"Parallel Old" is a compacting collector that uses multiple GC threads. Using the -XX flags for our collectors for jdk6.
"CMS"(Concurrent Mark Sweep) is a mostly concurrent, low-pause collector.
G1(Garbage First) straddles the young generation - tenured generation boundary because it is a generational collector only in the logical sense. G1 divides the heap into regions and during a GC can collect a subset of the regions.
Java內存模型(Java Memory Model),JMM,用來屏蔽掉各種硬件和操作系統之間內存訪問差異,以實現在各種平臺下一致的內存訪問效果。
JMM主要目標是定義程序中各個變量的訪問規則。即在虛擬機中將變量存儲到內存和從內存中取出變量。
所有變量都存儲在主內存(Main Memory),每個線程還有自己的工作內存(Working Memory)。
線程對變量的讀取、賦值等操作都必須在工作內存中進行。
線程間變量值的傳遞必須通過主內存來完成。
關于怎樣理解HotSpot JVM的基本原理就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。