JVM 介紹
本文介紹了JVM相關知識。內容僅供參考使用,有不足之處請及時指出,也歡迎大家交流探討。
JVM
JVM是Java Virtual Machine的縮寫,也就是java虛擬機器的意思。JVM是一種規範,其作用是將位元組碼解釋為相應的機器指令執行及對程式資源的管理和優化。

JVM 位置.png
JVM 知名實現
Sun HotSpot
目前應用最廣泛的JVM,起初由Longview Technologies公司開發,97年被Sun收購,首次釋出於Sun JDK 1.2,Sun JDK1.3及之後版本的預設虛擬機器。
Oracle JRockit
原名Bea JRockit,BEA公司02年從Appeal Virtual Machines收購獲得,專注於服務端應用,曾經號稱世界上速度最快的虛擬機器,BEA公司08年被Oracle收購。
IBM J9
J9是IBM公司開發的虛擬機器,其為IBM公司各種產品的執行平臺。
Sun Classic
該虛擬機器是JDK1.0時使用的虛擬機器,是各種虛擬機器的始祖。
Sun Exact
該虛擬機器由Sun HotSpot同時期開發,後被Sun HotSpot取代。
JVM JDK JRE 關係
Java程式設計語言,Java虛擬機器,Java API 類庫這三部分稱為JDK(Java Development Kit)。
JDK是Java開發的最小環境。
Java API類庫中的Java SE API子集和Java虛擬機器稱為JRE(Java Runtime Environment)。
JRE是Java執行的最小環境。
JVM 組成

JVM 組成.png
類載入器
類載入器負責將符合檔案結構的類檔案載入到記憶體中。
執行引擎
執行引擎也叫直譯器(Interpreter),類載入後會將指令和資料存放在記憶體中,執行引擎會解釋這些命令並和作業系統做互動,並負責資源的調配(滿足程式資源的需要並和提供資源的作業系統協調)。
本地介面
本地介面是為了與其他程式語言做互動設計的。其會在本地方法棧中記錄本地方法,在呼叫本地方法時執行引擎會去載入對應的本地庫包。例如Java驅動印表機。不過目前該方法使用並不多,其可以被Socket通訊,WebService等方法取代。
JVM 執行資料區域
JVM在執行程式時會將其管理的記憶體劃分為若干個區域。
程式計數器
執行緒不共享,每個執行緒都會有自己的程式計數器,其生命週期和執行緒一致。如果執行的是位元組碼方法,計數器中記錄的是當前執行指令的地址,如果執行的是Native方法,計數器值為空。程式計數器佔用記憶體很小,該記憶體區域是JVM規範中唯一一個沒有規定任何OutOfMemoryError的區域。
虛擬機器棧
執行緒不共享,每個執行緒都會有自己的虛擬機器棧,虛擬機器棧的生命週期與執行緒同步,棧的記憶體地址是不連續的。每一個方法呼叫時都會建立一個棧幀(Stack Frame)來儲存區域性變量表(基本資料型別和物件引用),操作棧,動態連結,方法出口等資訊,每個方法被呼叫到執行完成會對應一個棧幀的入棧和出棧。棧的大小有兩種方式,動態擴充套件和固定長度,當前大多數JVM為可動態擴充套件的。
JVM規範中,對該區域定義了兩個異常:如果執行緒請求的棧深度大於虛擬機器所允許的深度,則會丟擲StackOverflowError異常。如果擴充套件時無法獲得所需的記憶體,則會丟擲OutOfMemoryError異常。
本地方法棧
與虛擬機器棧作用相似,只不過服務物件換為了Native方法。Sun HotSpot虛擬機器中,本地方法棧和虛擬機器棧合二為一。該區域會丟擲StackOverflowError和OutOfMemoryError異常。
堆
執行緒共享,所有執行緒公用的記憶體區域,大多數情況下,堆是JVM所管理記憶體中最大的一塊,虛擬機器啟動時建立,存放物件例項,可以為物理上不連續的記憶體區域,只要邏輯上連續即可,堆記憶體大小有倆種方式,動態擴充套件和固定長度,當前主流的虛擬機器都是動態擴充套件的。堆記憶體使用不足時,會丟擲OutOfMemoryError異常,堆記憶體被GC管理。
方法區
執行緒共享,所有執行緒公用的記憶體區域,用來存放已被虛擬機器載入的類資訊,常量,靜態變數,即時編譯器編譯後的程式碼等。Java虛擬機器規範中將該區域描述為堆的一個部分,但該區域的別名為非堆(Non-Heap)。該區域不需要和堆一樣,可以使用物理上不連續的記憶體區域,也可以選擇動態擴充套件或者固定長度,該區域記憶體不足時,會丟擲OutOfMemoryError異常。
HotSpot虛擬機器使用永久代(PermanetGeneration)來實現方法區,並將GC分代收集擴充套件到方法區,GC可以選擇不實現。
JDK1.7中,部分永久代的資料遷移到了堆中,例如常量池,靜態變數。
JDK1.8中,HotSpot虛擬機器使用元空間(Metaspace)替代了永久代,部分原因是為了與JRockit融合,因為JRockit中並沒有永久代。元空間不再是JVM記憶體的一部分,其存在於直接記憶體中。
JVM 垃圾回收
垃圾回收簡稱GC(Garbage Collection),GC會對不再使用的記憶體進行回收。因為程式計數器,虛擬機器棧,本地方法隨執行緒的生命週期一致,故GC針對的是堆和方法區。
引用型別
- 強引用
物件只要存在強引用,GC就不會進行回收。Java中,Object object = new Object()就是強引用。
- 軟引用
標識有用但非必須的物件,系統發生記憶體溢位異常之前,會將該類物件列入回收範圍並進行第二次回收。可通過SoftReference類來實現。
- 弱引用
弱引用標識的物件在下一次垃圾回收時回收。當垃圾收集器工作時,無論記憶體是否足夠,都會將弱引用標識的物件。可通過WeakReference類來實現。
- 虛引用
被稱為幽靈引用或者幻影引用,其不會對物件的生命週期產生任何影響,其唯一作用就是被虛引用標識的物件被收集器回收時會收到一個系統通知。
判斷需要回收的記憶體
堆(物件)
-
引用計數演算法
-
根搜尋演算法(Java採用的演算法)
方法區(廢棄常量,無用的類)
-
如果沒有任何地方引用常量池中的常量,該常量會被回收。
-
無用類判斷標準
-
該類的所有例項被回收,堆中不存在其任何例項。
-
載入該類的ClassLoader被回收。
-
該類的java.lang.Class物件沒有在任何地方被引用,無法在任何地方通過反射訪問其方法。
-
垃圾收集演算法
-
標記-清除演算法
-
複製演算法
-
標記-整理演算法
-
分代收集演算法
垃圾收集器
-
Serial 收集器
-
ParNew 收集器
-
Parallel Scavenge 收集器
-
Serial Old 收集器
-
Parallel Old 收集器
-
CMS 收集器
-
G1 收集器