天天看點

JVM記憶體模型一、JVM 的作用二、JVM 組成三、JVM 記憶體模型

文章目錄

  • 一、JVM 的作用
    • 1、Java 程式的運作機制
    • 2、Java 如何實作平台無關性?
  • 二、JVM 組成
  • 三、JVM 記憶體模型
    • 1、PC 寄存寄
    • 2、方法區
    • 3、運作時常量池
    • 4、Java 虛拟機棧
    • 5、本地方法棧
    • 6、堆記憶體
本文内容基于目前使用最廣泛的 HotSpot JVM。

一、JVM 的作用

JVM,即 JAVA 虛拟機(Java virtual machine),是運作 Java 程式必不可少的工具。

JVM 實作了 Java 語言最重要的特征:平台無關性。

1、Java 程式的運作機制

程式員編寫的代碼都是源代碼(.java),不能直接執行,必須通過 javac 編譯成位元組碼檔案(.class),最後在 JVM 中運作。

JVM記憶體模型一、JVM 的作用二、JVM 組成三、JVM 記憶體模型

2、Java 如何實作平台無關性?

Java 語言很重要的一個優點就是具有平台無關性:“一次編寫,到處運作”,可以在 Windows、Solaris、Linux、MacOS 等各種作業系統平台上運作同樣的 java 代碼。

Java 實作平台無關性的關鍵就是 JVM。

因為 Java 程式不是直接運作在作業系統上,而是運作在 JVM 中。而我們在運作 java 程式之前必須先搭建好 java 環境,其實就是在不同的作業系統上安裝與系統對應的 JVM ,屏蔽了與具體平台相關的資訊,最終給使用者的感覺就是平台無關的。

二、JVM 組成

JVM 是通過在實際的計算機上仿真模拟各種計算機功能來實作的 java 虛拟機。

它由一套位元組碼指令集、一組寄存器、垃圾回收器、堆、棧、存儲方法域等組成,如下圖所示:

JVM記憶體模型一、JVM 的作用二、JVM 組成三、JVM 記憶體模型

翻譯成中文,如下所示:

JVM記憶體模型一、JVM 的作用二、JVM 組成三、JVM 記憶體模型

可以看出,JVM 主要由以下三部分組成:

JVM = 類加載器 classloader + 執行引擎 execution engine + 運作時資料區域 runtime data area
           

類加載器 classloader 把硬碟上的 class 檔案加載到 JVM 中的運作時資料區域中,由執行引擎負責執行,執行過程中産生的資料都放在運作時資料區。

JVM 運作時資料區 (Runtime Data Area) 其實就是指 JVM 在運作期間,對 JVM 記憶體空間進行管理和配置設定。

三、JVM 記憶體模型

JVM 在執行 Java 程式時,會把運作時資料區 (Runtime Data Area) 劃分為 6 個區域來存儲運作時資料,包括:堆記憶體(Heap Memory)、虛拟機棧/Java棧(Java Stacks)、本地方法棧(Native Method Stack)、PC 寄存寄(PC Registers)、方法區(Method Area)、運作時常量池。

JVM 記憶體模型如下圖所示:

JVM記憶體模型一、JVM 的作用二、JVM 組成三、JVM 記憶體模型

程式員寫的所有程式都被加載到運作時資料區域中,根據資料類型不同分别存放在 6 個記憶體區域中。

這些區域分别有各自的用途、生命周期,有些依賴虛拟機程序啟動而存在,有些依賴使用者線程的啟動和結束而建立和銷毀。

1、PC 寄存寄

PC 寄存寄(PC Registers),也稱為程式計數器。

每個線程都會有自己私有的程式計數器,它是一塊較小的記憶體空間,相當于目前線程所執行的位元組碼程式的行号訓示器。

程式計數器區域是唯一一個在 JVM 規範中沒有規定任何 OOM (OutOfMemoryError)情況的區域。

2、方法區

方法區,Method Area,是各個 線程共享 的記憶體區域,它用于存儲已被虛拟機加載的類資訊、常量、靜态變量等資料。

很多時候,也把方法區稱為 “永久代”(Permanent Generation)。

根據 JVM 規範,當方法區無法滿足記憶體配置設定需求時,可能抛出

OutOfMemoryError

異常。

3、運作時常量池

運作時常量池(Runtime Constant Pool)是方法區中的一部分,其中存放的是類中固定的常量資訊、方法和域的引用資訊。

該區域受方法區記憶體的限制,當常量池無法再申請到記憶體時會抛出

OutOfMemoryError

異常。

4、Java 虛拟機棧

Java 虛拟機棧,即 Java Virtual Machine Stack,通常簡稱為 VM Stack 或 Java Stack 或 Stack --「棧」,它描述了 Java 方法執行的記憶體模型。

虛拟機棧具有如下特點:

  • 線程私有,生命周期和線程相同;
  • 每個方法在執行時都會建立一個棧幀 (Stack Frame),用于存儲 局部變量表(方法中定義的變量)、操作數棧、動态連結、方法出口等資訊。
  • 棧幀随着方法調用而建立,随着方法結束而銷毀——無論方法是正常完成還是異常完成(抛出了在方法内未被捕獲的異常)都算作方法結束。
  • 每個方法從調用直至執行完成的過程,就是對應着一個棧幀在棧中入棧和出棧的過程。

在 JVM 規範中對這塊區域規定了兩種異常情況:

  • 如果線程請求的棧深度大于 JVM 允許的深度,則抛出

    StackOverflowError

    異常;
  • 如果虛拟機棧動态擴充時,無法申請到足夠的記憶體,則抛出

    OutOfMemoryError

    異常。

5、本地方法棧

本地方法棧,即

Native Method Stack

,用于執行 Native 方法(簡單的說,Native 方法就是用 java 調用非 java 代碼的接口,一般是針對一些系統底層的代碼)。它與虛拟機棧的作用相似。

Native Method Stack

VM Stack

的差別:

  • VM Stack

    是為執行 java 方法服務的;
  • Native Method Stack

    是為執行本地方法(非 java 代碼)服務的;
  • 二者其它的作用相似。

在目前最流行的 Sun HotSpot 虛拟機中,直接把虛拟機棧和本地方法棧合二為一。

與 Java 虛拟機棧一樣,本地方法棧也會抛出

StackOverflowError

OutOfMemoryError

異常。

6、堆記憶體

堆記憶體,即

Heap Memory

,是 JVM 管理的記憶體中最大的一塊。

堆記憶體具有如下主要特點:

  • 在虛拟機啟動時被建立;
  • 被所有線程共享的一塊存儲區域;
  • 幾乎所有的對象執行個體和數組都要在堆上配置設定。

堆中存儲的對象,無需、也無法顯式地被銷毀。它們被自動管理記憶體系統(Automatic Storage Management System,也即是常說的 「Garbage Collector(垃圾回收器)」)所管理。

堆記憶體的大小可以是固定的,也可以随着程式執行的需求動态擴充,并在不需要過多空間時自動收縮。

根據 JVM 規範,當在堆中沒有記憶體完成執行個體配置設定,并且堆也無法再擴充時,将會抛出

OutOfMemoryError

異常。

由于篇幅限制,在下一篇文章中對堆記憶體進一步探讨。