天天看點

Java虛拟機(一) - 記憶體區域與記憶體溢出異常

運作時資料區

1、 PC寄存器/程式計數器(Program Counter Register)

概念:

程式計數器是一塊較小的記憶體空間,它可以看作是目前線程所執行的位元組碼的行号訓示器。

由于Java虛拟機的多線程是通過線程輪流切換并配置設定處理器執行時間的方式來實作的,在任何一個确定的時刻,一個處理器(多核處理器來說是一個核心)都隻會執行一條線程中的指令。

為了線程切換後能恢複到正确的執行位置,需要程式計數器記錄目前線程運作的位元組碼指令位址。

每個線程都有一個獨立的程式計數器。

線程私有記憶體:各個線程之間互不影響,獨立存儲。

程式計數器就屬于線程私有記憶體

異常:

不會有OutOfMemoryError的情況

2、Java虛拟機棧(Java Vrtual Machine Stacks)

類型:線程私有

概念:

描述Java方法執行的記憶體模型。

每個方法在執行時都會建立一個棧幀用于存儲局部變量表、操作數棧、動态連結、方法出口等資訊。

每個方法從調用直至執行完成的過程,對應着一個棧幀在虛拟機棧中入棧到出棧的過程。

  • 局部變量表

    存放:基本資料類型、對象引用(reference類型)和returnAddress類型(指向了一條位元組碼指令的位址)

    64位長度的資料(long和double)會占用2個局部變量空間(Slot),其餘類型都占1個。

異常:

(1)如果線程請求的棧深度大于虛拟機所允許的深度,抛出 StackOverflowError

(2)如果虛拟機可以動态擴充(大部分都可以),如果擴充時無法申請到足夠的記憶體,抛出 OutOfMemoryError

3、本地方法棧

本地方法棧類似于Java虛拟機棧

有些虛拟機(例如Sun HotSpot虛拟機)直接把Java虛拟機棧和本地方法棧合二為一

差別:

本地方法棧執行native方法

Java虛拟機棧執行Java方法

4、Java堆(Java Heap)

類型:線程共享的記憶體區域

概念:

Java虛拟機所管理的記憶體中最大的一塊。

Java堆的唯一目的就是存放對象執行個體。

Java堆可以處于實體上不連續的記憶體空間中,隻要邏輯上是連續的即可,就像磁盤空間一樣。

通過-Xmx和-Xms控制堆記憶體的擴充。

Java堆時垃圾手機和管理的主要區域,有時候也被稱為 “GC堆”。

異常:

如果在堆中沒有記憶體完成執行個體配置設定,并且堆無法再擴充時,抛出OutOfMemoryError

5、方法區

類型:線程共享的記憶體區域

概念:

用于存儲每個類的結構資訊。

例如:運作時常量池(接下來會講)、字段、方法資料、構造函數和普通方法的位元組碼内容。還包括一些在類、執行個體、接口初始化時用到的特殊方法。

方法區是堆的邏輯組成部分,但差別于Java堆。虛拟機在方法區可以不實作垃圾收集與壓縮。

注意:有的部落格上寫 “方法區又稱靜态區”,但本人并沒有在權威的資料裡看到這個翻譯,是以建議大家可以結合這個名詞了解,但不要這麼稱呼。(如果有在權威權威資料裡看到這個翻譯,敬請告知)

異常:

當方法區無法滿足記憶體配置設定需求時,抛出,OutOfMemoryError異常。

6、運作時常量池

概念:

方法區的一部分,用于存放編譯器生成的各種字面量和符号引用。

在程式運作期間,也可能有新的常量放入池中。

  • 字面量
int i = 1;把整數1指派給int型變量i,整數1就是Java字面量,
String s = "abc";中的abc也是字面量。
           
  • 符号引用

    符号引用以一組符号來描述所引用的目标, 符号可以是任何形式的字面量, 隻要使用時能夠無歧義的定位到目标即可. 例如, 在Java中, 一個Java類将會編譯成一個class檔案. 在編譯時, Java類并不知道所引用的類的實際位址, 是以隻能使用符号引用來代替. 比如org.simple.People類引用了org.simple.Language類, 在編譯時People類并不知道Language類的實際記憶體位址, 是以隻能使用符号org.simple.Language來表示Language類的位址.

  • 直接引用

    直接引用可以是:

    直接指向目标的指針.(個人了解為: 指向方法區中類對象, 類變量和類方法的指針)

    相對偏移量. (指向執行個體的變量, 方法的指針)

    一個間接定位到對象的句柄.

    我覺得直接引用說白了, 就是程式運作時可以定位到引用的東西(類, 對象, 變量或者方法等)的位址.

其他

1、直接記憶體

直接記憶體不是Java虛拟機運作時資料區的一部分。

在JDK1.4中,新加入的NIO類,引入了一種基于通道(Channel)與緩沖區(Buffer)的I/O方式,它可以使用Native函數庫直接配置設定堆外記憶體,通過存儲在堆中的DirectByteBuffer對象作為這塊記憶體的引用進行操作。

異常

如果各個記憶體區域(Java虛拟機記憶體區域)總和大于實體記憶體限制(實體和作業系統級的限制),會導緻動态擴充時 抛出,OutOfMemoryError。

[1] 周志明 · 深入了解Java虛拟機 :機械工業出版社

[2] 愛飛翔 周志明 等譯 · Java虛拟機規範(Java SE 8 版)機械工業出版社

[3] 字面量,符号引用,直接引用的概念摘自 https://blog.csdn.net/BraveLoser/article/details/82500474