JVM便祕攻略一

JVM官方文檔01

JVM官方文檔02

目錄

1 概述

1.1 操作系統是啥

1.2 JVM是啥

1.3 JVM嘎哈的

1.4 JVM的生命週期

1.5 JVM中使用的數據類型

1.5.1 原始數據類型(primitive types)

1.5.2 引用數據類型(reference type)

2 Java虛擬機內存劃分

2.1 Java虛擬機內存區域

2.2 程序計數器Program Counter Register

2.3 Java虛擬機棧(Java Virtual Machine Stacks)

2.4 本地方法棧(Native Method Stack)

2.5 堆(Heap)

2.6 方法區(Method Area)

3 JVM類加載機制

3.1 熱身

3.2 類的生命週期

3.2.1 加載

3.2.2 驗證

3.2.3 準備

3.2.4 解析

3.2.5 初始化


1 概述

1.1 操作系統是啥

操作系統(Operating System)是計算機系統中的一個系統軟件,負責組織和管理計算機的軟硬件資源,是資源的管理者。主要功能有進程線程管理,存儲管理,文件管理,I/O設備管理和用戶接口。

硬件資源:CPU,存儲器,設備(I/O設備,時鐘,網卡等)

軟件資源:磁盤上的文件,各類管理信息等

跨平臺:即不依賴於操作系統,也不依賴於硬件環境。一個操作系統下開發的應用,放到另一個操作系統下依然可以運行。

1.2 JVM是啥

JVM(Java Virtual Machine)實質上也是一個計算機系統軟件,是基於物理機所安裝的操作系統上又虛擬出來的一個子操作系統,是資源的管理者,不同平臺有不同的版本。

1.3 JVM嘎哈的

在不同平臺下安裝對應的JVM,就可以運行字節碼文件。不同平臺下編譯生成的字節碼是一樣的,但由JVM解釋生成的機器碼是不一樣的。所以說,跨平臺的是Java程序,而不是JVM。

小實踐

Java源程序——編譯——>.class字節碼文件

命令:javac xxx.java

.class字節碼文件——JVM的Java解析器——>特定平臺下的機器碼

命令:java xxx

1.4 JVM的生命週期

main()方法是程序的起點,它被執行的線程初始化爲程序的初始線程(不是守護線程)。程序中其他的線程都由它來啓動。

Java中的線程分爲兩種

守護線程(daemon /'diːmən/)JVM自己使用的線程。比如負責垃圾收集的線程。

普通線程(non-daemon)

1.5 JVM中使用的數據類型

1.5.1 原始數據類型(primitive types)

數據類型

整數型:byte,short,int,long

浮點型:float,double

字符類型:char

布爾類型:boolean

取值範圍

存放整數的存儲單元中,最左邊一位是符號位,0表示數值爲正,1表示數值爲負

計算機使用補碼來存放二進制數

正數:補碼=原碼

負數:補碼=除符號位,其它每位取反,末位+1

1.5.2 引用數據類型(reference type)

數組(array),類(class),接口(interface)

用來引用被動態創建的對象。當引用類型引用null時,表示沒有引用任何對象

2 Java虛擬機內存劃分

2.1 Java虛擬機內存區域

2.2 程序計數器Program Counter Register

先穿插一些計算機組成原理的知識

CPU控制器的簡化模型

Each Java Virtual Machine thread has its own PC register. At any point, each Java Virtual Machine thread is executing the code of a single method, namely the current method for that thread. If that method is not native, the PC register contains the address of the Java Virtual Machine instruction currently being executed. If the method currently being executed by the thread is native, the value of the Java Virtual Machine's PC register is undefined.

JVM中的PC的是正在執行的字節碼指令的地址,而CPU的PC寄存器指向的是下一條指令的地址。

PC屬於線程私有的,不可共享,否則會導致計數混亂,無法準確的執行當前線程需要執行的語句。

2.3 Java虛擬機棧(Java Virtual Machine Stacks)

虛擬機棧中的元素爲棧幀(Stack Frame),棧幀用來來存儲局部變量表、操作棧、動態鏈接、方法出口等信息。Java中每個方法從調用直至執行完成的過程,都對應着一個棧幀在虛擬機棧中出棧和入棧的過程。

如果線程請求的棧深度 > 虛擬機所允許的深度,將拋出StackOverflowError異常

如果虛擬機棧可以動態擴展,但擴展時無法申請到足夠的內存,將拋出OutOfMemoryError異常

2.4 本地方法棧(Native Method Stack)

本地方法棧用來執行本地方法,拋出異常情況與虛擬機棧一樣。而虛擬機棧用來執行java方法

本地方法可以用各種編程語言來實現。好比在Java程序中調用C語言編寫的本地方法。

 

2.5 堆(Heap)

堆是JVM中內存最大的一塊區域,被所有線程共享。Java堆用來存儲對象實例,是垃圾收集器管理的主要區域。由於現代垃圾收集齊採用的是分代收集算法,所以Java堆也分爲新生代和老年代。

2.6 方法區(Method Area)

方法區與java堆一樣,是各個線程共享的內存區域,用於存儲已被虛擬機加載的類信息、常量、靜態變量、class文件等數據。GC也會對該區域進行回收,如常量池的清理。

運行時常量池(Runtime Constant Pool)是方法區的一部分,用於存放編譯器生成的各種字面量和符號引用,這部分內容將在類加載後進入方法區的常量池中存放。

當常量池無法再申請到內存時會拋出OutOfMemoryError異常。

延伸:

String s = new String("xyz"); 在運行時涉及幾個實例

兩個,一個是字符串字面量"xyz"所對應的,駐留(intern)在一個全局共享的字符串常量池中的實例,另一個是通過new String(String)創建並初始化的,內容與"xyz"相同的實例。

對於HotSpot虛擬機來說,方法區是用“永久代”來實現的。因爲容易遇到內存溢出問題。字符串常量池在JDK1.7之前是存在於方法區的。自JDK1.7開始,永久代中的字符串常量池被移到堆中,而元信息則被移到本地內存中的“元空間(Metaspace)”中,並且會被垃圾回收機制回收。

3 JVM類加載機制

3.1 熱身

JVM把描述類的數據從Class文件加載到內存,並對數據進行校驗,轉換解析和初始化,最終形成可被虛擬機直接使用的Java類型。類class只有被加載到JAM後才能運行。

Java語言裏,類型的加載,連接和初始化都是在程序運行期間完成的。

不同於C語言程序執行過程

3.2 類的生命週期

加載,驗證,準備,初始化和卸載的順序是確定的,解析階段不一定。

3.2.1 加載

加載的過程由類加載器來完成,即由ClassLoader和它的子類來實現。類加載器本身也是一個類,其實質是把類文件從硬盤讀取到內存。

類的加載方式隱式加載與顯示加載

隱式加載:使用new等方式創建對象時,會隱式地調用類的加載器把對應的類加載到JVM

顯示加載:直接調用class.forName()來把所需的類加載到JVM

Java語言中,類的加載是動態的,程序啓動時,只把需要的類加載到JVM,至於其他類,在需要時才加載

Java語言中,類分成3種:系統類,擴展類和自定義類。且分別對應不同類型的加載器。

類加載器

Bootstrap Loader:負責加載系統類。由C++編寫。

ExtClassLoader:負責加載擴展類。由Java編寫。

AppClassLoader:負責加載應用類。由Java編寫。

用戶自定義類加載器:java.lang.ClassLoader的子類,用戶可以定製類的加載方式。每一個類都包含了加載它的ClassLoader的一個引用——getClassLoader()。若返回null,證明加載它的是根加載器Bootstrap。

類加載器的加載順序

類加載器加載Class的過程

木有!

3.2.2 驗證

虛擬機規範:驗證輸入的字節流是否符合Class文件的存儲格式,否則拋出java.lang.VerifyError異常。

文件格式驗證:驗證字節流是否符合Class文件格式的規範,且能被當前版本的虛擬機處理。經過該階段的驗證,字節流進入內存的方法區進行存儲。

元數據驗證:對類的元數據信息進行語義校驗,保證不存在不符合Java語言規範的元數據信息。

字節碼驗證:進行數據流和控制流分析,對類的方法體進行校驗分析,防止傷害產生傷害虛擬機安全的行爲。

符號引用驗證:對常量池中各種符號引用的信息進行匹配性的校驗。

3.2.3 準備

3.2.4 解析

3.2.5 初始化

下面情況必須立即對類進行“初始化”

延伸:

(1)運行一個Java程序時,JVM會爲該程序創建一個進程,併爲該進程分配一個唯一標識及進程控制塊PCB,同時也會分配一塊虛擬的內存地址空間。

   

(2)類加載器Class Loader加載java程序類文件到方法區。方法區存放加載過的類的基本信息、常量、靜態變量等。方法區是線程共享的。

(3)類加載完成後,主線程運行static main()時在虛擬機棧中建棧幀,壓棧。

(4)執行到new Object()時,在堆heap區爲對象分配地址空間,然後執行類的構造函數初始化

學完了?學海無涯。

下面跳轉至《JVM便祕攻略二》                       


本文學習自

《深入理解java虛擬機》

學堂在線-清華大學-許斌《JAVA程序設計進階》

操作系統核心原理

北大陳向羣《操作系統》

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章