溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么用最通俗的方法講解JVM內(nèi)存模型

發(fā)布時間:2021-10-20 16:41:17 來源:億速云 閱讀:129 作者:柒染 欄目:大數(shù)據(jù)

本篇文章為大家展示了怎么用最通俗的方法講解JVM內(nèi)存模型,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

什么是JVM?什么是JVM內(nèi)存模型?

備注:本文講的基于JDK1.8,且1.8之前和之后差距略大,本文對1.8之前的版本只會略微介紹.

JVM說白了,就是個程序,而這個程序運(yùn)行起來后,就是臺計算機(jī),而且和我們平時使用的計算機(jī)非常相似,他就是一臺虛擬計算機(jī). 那什么是JVM內(nèi)存模型?就是幾個大神寫了一個在計算機(jī)上運(yùn)行的虛擬計算機(jī)的內(nèi)存模型. 那計算機(jī)的內(nèi)存模型是什么樣的?

怎么用最通俗的方法講解JVM內(nèi)存模型

各部分功能,相信不從事該行業(yè)的人都有相當(dāng)一部分知道他的大概作用,但我們還是粗略解釋一下 名稱|速度|介紹 --|--|-- 寄存器|速度特別快|暫存指令等短小精干的數(shù)據(jù). 棧|速度塊|空間連續(xù). 堆|速度慢|空間不連續(xù),但比硬盤可快多了. 硬盤|速度最慢|就是個倉庫.

那么!本篇文章就會在此圖中進(jìn)行講解 下面多圖慎入!

添加一個虛擬機(jī)

接下來,我們在這個電腦上添加一個虛擬機(jī) 既然我們說虛擬機(jī)和計算機(jī)是一樣的,那我們就把上述的堆棧等一堆東西都建一個放進(jìn)電腦里. 那么放到哪呢?

  • 寄存器放不了.

  • 棧太小.

  • 堆可以,空間不連續(xù)我們可以自己搞.

  • 硬盤是一個物理存儲,也不行.

由上得出,放到堆里,于是有了下面的樣子.

怎么用最通俗的方法講解JVM內(nèi)存模型

這個圖也很好懂,就是把寄存器,堆,棧,硬盤都放到操作系統(tǒng)的堆中了. OK,我們把虛擬機(jī)放進(jìn)來了,那么接下來呢?好像沒什么頭緒. 既然虛擬機(jī)有了,那我們把它運(yùn)行起來吧. 現(xiàn)在有兩個問題

  1. 它是怎么運(yùn)行的? JVM就是個C語言程序

  2. 這個程序的功能是什么? 運(yùn)行的是.class文件.

簡單的說,這個程序在運(yùn)行的時候,會啟動一個功能,叫類加載器,這個類加載器加載.class文件后,會把文件中的不同內(nèi)容,放入到堆棧這些不同的區(qū)域中. 那么這些區(qū)域都分別放了寫什么呢? 區(qū)域名稱|存儲內(nèi)容|特點(diǎn) :-|:-|:- 寄存器|代碼運(yùn)行到了哪一行(行話:當(dāng)前線程正在執(zhí)行的字節(jié)碼的行號指示器)|空間小,不會溢出,隨線程生滅 本地方法棧|JVM執(zhí)行的native方法|HotSpot虛擬機(jī)不區(qū)分虛擬機(jī)棧和本地方法棧,兩者是一塊的 棧|1.局部變量 2.操作棧 3,動態(tài)鏈接 4.返回地址|先進(jìn)后出,桶式結(jié)構(gòu) 堆|1.實(shí)例對象 2.數(shù)組 3.字符串常量池 4.靜態(tài)常量|垃圾回收器會回收沒被引用的對象和數(shù)組 元數(shù)據(jù)區(qū)(1.8前叫方法區(qū))|1.類信息 2.編譯后的代碼 3.運(yùn)行時常量池|1.7前叫方法區(qū),在堆中稱為非堆,1.7后放入了本地內(nèi)存,叫元數(shù)據(jù)區(qū) 接下來我一個個詳細(xì)解釋一下

1. 本地方法棧 (線程私有)

這個知識點(diǎn)比較簡單,==本地方法棧服務(wù)的對象是JVM執(zhí)行的native方法== 總之,線程開始調(diào)用本地方法時,不受JVM約束.太多的nativa方法會影響虛擬機(jī)的可移植性.

2. 堆 (線程共有)

為什么把堆放在棧前講,是因?yàn)檫@部分比較重要,而且是基礎(chǔ)部分.

堆中的內(nèi)容是線程共有的,所有線程訪問堆是同一個區(qū)域.

2.1 存放內(nèi)容

堆中存放的數(shù)據(jù)是對象實(shí)例和數(shù)組 例如:

User user = new User();//User是系統(tǒng)中常見的Model類
             ↑
             └─ new 出來的這個東西,就在堆中,controller同理
                     ↓
UserController uc = new UserController();//mvc模式下常見的類

堆最大,里面的東西也最多.里面的東西越放越多,但內(nèi)存就那么大,總有放滿的一天,于是,堆中沒用的東西就要被回收. 于是這群大神將堆分了幾個區(qū),分別為:

字符串常量池 : 其實(shí)是C++寫的一個hash表,所有的字符串都保存在常量池中.
			 在http://hg.openjdk.java.net/jdk6/jdk6/hotspot/file/9732f3600a48/src/share/vm/classfile/symbolTable.hpp定義
老年代 : 比例約為 2
新生代 : 比例約為 1
	其中新生代又分為:
	Eden區(qū)        : 占新生代的 8/10
	Suivivor 0 區(qū) : 占新生代的 1/10
	Suivivor 1 區(qū) : 占新生代的 1/10
//當(dāng)然大小和比例可以通過命令來修改

如圖:

怎么用最通俗的方法講解JVM內(nèi)存模型

再換一張官方的圖

怎么用最通俗的方法講解JVM內(nèi)存模型

這張圖可以使用JDK自帶的 : jdk/bin/jvisualvm.exe.
打開后選擇 - 工具 - 插件 - 可用插件 - 安裝VisualGC - 重啟軟件 - 左側(cè)選擇JVM進(jìn)程 - 右邊就會顯示Visual GC

怎么用最通俗的方法講解JVM內(nèi)存模型

那么JVM對各個區(qū)域是如何使用的呢?

  1. 絕大部分對象生成時都在Eden區(qū),當(dāng)Eden區(qū)裝填滿的時候,會觸發(fā)Young GC。

  2. Young GC的時候,在Eden區(qū)執(zhí)行清除,沒有被引用的對象直接回收,依然存活的對象會被移送到Survivor區(qū).

Survivor 區(qū)分為S0和S1兩塊內(nèi)存空間,送到哪塊空間呢?

  1. 每次Young GC的時候,將存活的對象復(fù)制到未使用的那塊空間,然后將當(dāng)前正在使用的空間完全清除,交換兩塊空間的使用狀態(tài).

  2. 如果Young GC要移送的對象大于Survivor區(qū)容量上限,則直接移交給老年代.

那會不會有頑強(qiáng)對象一直留在Surivivor區(qū)呢? 答案是不會的,每個對象都有一個計數(shù)器,每次YGC都會加1.計數(shù)器默認(rèn)為15,如果某個對象在Survivor 區(qū)交換14次之后,則晉升至老年代.

2.2 生命周期

對象在堆的生命周期如下:

怎么用最通俗的方法講解JVM內(nèi)存模型

至于虛擬機(jī)如何將對象標(biāo)記為未被引用,可以查看 : GC算法.

2.3 另外說句題外話.

為什么計算機(jī)學(xué)科中將這塊區(qū)域叫為堆(heap),而不是其他任何名詞呢? 其實(shí)是因?yàn)檫@里的數(shù)據(jù)是不連續(xù)的,也就是分配內(nèi)存地址是這里一個,那里一個. 如圖:

怎么用最通俗的方法講解JVM內(nèi)存模型

堆的內(nèi)存是不整齊的,是亂的.是非連續(xù)的,就是一堆雜亂的東西,所以稱之為堆.

3. 棧 (線程私有)

棧中存放的是什么? 棧中其實(shí)就是和當(dāng)前執(zhí)行方法相關(guān)的數(shù)據(jù). 棧首先有個首要的特點(diǎn),他是桶狀的,是一個先入后出(FILO)的數(shù)據(jù)結(jié)構(gòu).如圖:

怎么用最通俗的方法講解JVM內(nèi)存模型

但棧是線程私有的,而我們的系統(tǒng)通常不只有一個線程,所以棧實(shí)際中應(yīng)當(dāng)是這樣的. 如圖:

怎么用最通俗的方法講解JVM內(nèi)存模型

3.1 存放內(nèi)容

那圖中這些都是什么呢?我們來結(jié)合圖來說:

  1. 空棧   : 首先棧中原本是空的

怎么用最通俗的方法講解JVM內(nèi)存模型

  1. 創(chuàng)建?! ? 在某個線程創(chuàng)建時,虛擬機(jī)會為線程創(chuàng)建一個該線程私有的棧.

怎么用最通俗的方法講解JVM內(nèi)存模型

  1. 創(chuàng)建棧幀 : 線程開始執(zhí)行到第一個方法時,就會在棧中創(chuàng)建一個棧幀,而最新創(chuàng)建的棧幀稱為當(dāng)前棧幀

怎么用最通俗的方法講解JVM內(nèi)存模型

棧幀中存儲的是該方法的一系列信息,包括如下:

1. 局部變量表
	用于存放方法參數(shù)和方法內(nèi)部定義的局部變量
	局部變量表的容量以變量槽 [Slot] 為最小單位。
	在編譯期由Code屬性中的 [max_locals] 確定局部變量表的大小.
	
2. 操作數(shù)棧
	可以理解成在哪里執(zhí)行當(dāng)前的這一行代碼.
	
3. 動態(tài)鏈接
	在運(yùn)行時將類常量池中的符號引用轉(zhuǎn)換為直接引用.
	簡單來說,就是我們的類在編譯好后,并不知道其中的代碼所調(diào)用的方法的地址是什么.
	只有在執(zhí)行到該方法時,才知道調(diào)用的具體是哪個實(shí)例的方法.

4. 方法返回地址
	其實(shí)就是標(biāo)記一個退出的指令,或是遇到異常.則返回到上層棧幀.
	
	下面是術(shù)語,可以加深理解
	當(dāng)一個方法開始執(zhí)行后,只有兩種方式可以退出,一種是遇到方法返回的字節(jié)碼指令;一種是遇見異常,并且這個異常沒有在方法體內(nèi)得到處理。
	無論采用何種退出方式,在方法退出之后,都需要返回到方法被調(diào)用的位置,程序才能繼續(xù)執(zhí)行,方法返回時可能需要在棧幀中保存一些信息,用來	幫助恢復(fù)它的上層方法的執(zhí)行狀態(tài)。一般來說,方法正常退出時,調(diào)用者的PC計數(shù)器的值可以作為返回地址,棧幀中很可能會保存這個計數(shù)器值。而方法異常退出時,返回地址是要通過異常處理器表來確定的,棧幀中一般不會保存這部分信息。
	方法退出的過程實(shí)際上就等同于把當(dāng)前棧幀出棧,因此退出時可能執(zhí)行的操作有:恢復(fù)上層方法的局部變量表和操作數(shù)棧,把返回值(如果有的話)壓入調(diào)用者棧幀的操作數(shù)棧中,調(diào)整PC計數(shù)器的值以指向方法調(diào)用指令后面的一條指令等。

Java在執(zhí)行時,,就是將各種指令往棧中寫入和提取

3.2 生命周期

查看一段代碼的字節(jié)碼可以更好的理解JVM是如何對操作數(shù)棧和局部變量表進(jìn)行操作的.

package com.jasmine.Java高級.JVM.字節(jié)碼;

public class TestJVMStack {
    public static int a = 123;
    public int simpleMethod(){
        int x = 13;
        int y = 14;
        int z = x + y;

        return z;
    }

    public static void main(String[] args) {
        TestJVMStack s = new TestJVMStack();
        System.out.println(s.simpleMethod());
    }
}

上述代碼的字節(jié)碼為:(略長,不想了解可直接到下面看對于操作棧的操作.)

Classfile /E:/WorkSpace/Idea/MyJava/target/classes/com/jasmine/Java高級/JVM/字節(jié)碼/TestJVMStack.class
  Last modified 2019-8-27; size 854 bytes
  MD5 checksum 15fab830f998782e5087b8626274d45c
  Compiled from "TestJVMStack.java"
public class com.jasmine.Java高級.JVM.字節(jié)碼.TestJVMStack
  minor version: 0
  major version: 52
  /*
  類的訪問標(biāo)識
  ACC_PUBLIC:代表public
  ACC_SUPER :用于兼容早期的編譯器,新編譯器都設(shè)置該標(biāo)記.
  */
  flags: ACC_PUBLIC, ACC_SUPER
  // 類常量池,也叫 Class常量池
  // 第一列為常量類型
  // 第二列表示引用的常量或者utf8類型常量值
  // 如#1的類型是class,引用的是#2的值
Constant pool:
   #1 = Class              #2             // com/jasmine/Java高級/JVM/字節(jié)碼/TestJVMStack
   #2 = Utf8               com/jasmine/Java高級/JVM/字節(jié)碼/TestJVMStack
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               <clinit>       //代表是類初始化階段
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Fieldref           #1.#11         // com/jasmine/Java高級/JVM/字節(jié)碼/TestJVMStack.a:I
  #11 = NameAndType        #5:#6          // a:I
  #12 = Utf8               LineNumberTable
  #13 = Utf8               LocalVariableTable
  #14 = Utf8               <init>         // 代表是實(shí)例初始化階段,說白了就是構(gòu)造方法
  #15 = Methodref          #3.#16         // java/lang/Object."<init>":()V
  #16 = NameAndType        #14:#8         // "<init>":()V
  #17 = Utf8               this
  #18 = Utf8               Lcom/jasmine/Java高級/JVM/字節(jié)碼/TestJVMStack;
  #19 = Utf8               simpleMethod
  #20 = Utf8               ()I
  #21 = Utf8               x
  #22 = Utf8               y
  #23 = Utf8               z
  #24 = Utf8               main
  #25 = Utf8               ([Ljava/lang/String;)V
  #26 = Methodref          #1.#16         // com/jasmine/Java高級/JVM/字節(jié)碼/TestJVMStack."<init>":()V
  #27 = Fieldref           #28.#30        // java/lang/System.out:Ljava/io/PrintStream;
  #28 = Class              #29            // java/lang/System
  #29 = Utf8               java/lang/System
  #30 = NameAndType        #31:#32        // out:Ljava/io/PrintStream;
  #31 = Utf8               out
  #32 = Utf8               Ljava/io/PrintStream;
  #33 = Methodref          #1.#34         // com/jasmine/Java高級/JVM/字節(jié)碼/TestJVMStack.simpleMethod:()I
  #34 = NameAndType        #19:#20        // simpleMethod:()I
  #35 = Methodref          #36.#38        // java/io/PrintStream.println:(I)V
  #36 = Class              #37            // java/io/PrintStream
  #37 = Utf8               java/io/PrintStream
  #38 = NameAndType        #39:#40        // println:(I)V
  #39 = Utf8               println
  #40 = Utf8               (I)V
  #41 = Utf8               args
  #42 = Utf8               [Ljava/lang/String;
  #43 = Utf8               s
  #44 = Utf8               SourceFile
  #45 = Utf8               TestJVMStack.java
{
  // 代表有一個靜態(tài)變量a,修飾是public static
  public static int a;
    descriptor: I
    flags: ACC_PUBLIC, ACC_STATIC

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      // stack     : 最大操作數(shù)棧,JVM運(yùn)行時會根據(jù)這個值來分配棧幀(Frame)中的操作棧深度,此處為1
      // locals    : 局部變量所需的存儲空間,單位為Slot,Slot是虛擬機(jī)為局部變量分配內(nèi)存時所使用的最小單位,為4個字節(jié)大小.
      // args_size : 方法參數(shù)的個數(shù),這里是0
      stack=1, locals=0, args_size=0
         0: bipush        123
         2: putstatic     #10                 // Field a:I
         5: return
      // LineNumberTable 該屬性的作用是描述源碼行號與字節(jié)碼行號(字節(jié)碼偏移量)之間的對應(yīng)關(guān)系。
      LineNumberTable:
        line 60: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature

  public com.jasmine.Java高級.JVM.字節(jié)碼.TestJVMStack();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #15                 // Method java/lang/Object."<init>":()V
         4: return
      // LineNumberTable 該屬性的作用是描述源碼行號與字節(jié)碼行號(字節(jié)碼偏移量)之間的對應(yīng)關(guān)系。
      LineNumberTable:
        line 6: 0
      // LocalVariableTable 該屬性的作用是描述幀棧中局部變量與源碼中定義的變量之間的關(guān)系。
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/jasmine/Java高級/JVM/字節(jié)碼/TestJVMStack;

  public int simpleMethod();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      // 這里普通的方法參數(shù)的個數(shù)為1是因?yàn)樗蓄愔械姆椒ǘ加袀€隱藏參數(shù)this
      stack=2, locals=4, args_size=1
         /*******************************************************
          * 對操作數(shù)棧的操作主要看這里,下面有對這段的詳細(xì)描述
          ******************************************************/
         0: bipush        13  
         2: istore_1          
         3: bipush        14  
         5: istore_2          
         6: iload_1           
         7: iload_2           
         8: iadd              
         9: istore_3          
        10: iload_3           
        11: ireturn           
      LineNumberTable:
        line 62: 0
        line 63: 3
        line 64: 6
        line 66: 10
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      12     0  this   Lcom/jasmine/Java高級/JVM/字節(jié)碼/TestJVMStack;
            3       9     1     x   I
            6       6     2     y   I
           10       2     3     z   I

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #1                  // class com/jasmine/Java高級/JVM/字節(jié)碼/TestJVMStack
         3: dup
         4: invokespecial #26                 // Method "<init>":()V
         7: astore_1
         8: getstatic     #27                 // Field java/lang/System.out:Ljava/io/PrintStream;
        11: aload_1
        12: invokevirtual #33                 // Method simpleMethod:()I
        15: invokevirtual #35                 // Method java/io/PrintStream.println:(I)V
        18: return
      LineNumberTable:
        line 70: 0
        line 71: 8
        line 72: 18
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      19     0  args   [Ljava/lang/String;
            8      11     1     s   Lcom/jasmine/Java高級/JVM/字節(jié)碼/TestJVMStack;
}
SourceFile: "TestJVMStack.java"

上述字節(jié)碼中的下段代碼就是JVM對操作棧的執(zhí)行順序.

         // 對應(yīng)代碼 13;
         0: bipush        13  // 將一個8位帶符號整數(shù) 13 壓入操作棧頂
         // 對應(yīng)代碼 x = 13;
         2: istore_1          // 從棧頂彈出,并將int類型值存入局部變量表的slot_1中
         // 對應(yīng)代碼 14;
         3: bipush        14  // 將一個8位帶符號整數(shù) 14 壓入操作棧頂
         // 對應(yīng)代碼 y = 14;
         5: istore_2          // 從棧頂彈出,并將int類型值存入局部變量表的slot_2中
         // 對應(yīng)代碼 x;
         6: iload_1           // 從局部變量表的slot_1中裝載int類型值,壓入操作棧頂
         // 對應(yīng)代碼 y;
         7: iload_2           // 從局部變量表的slot_2中裝載int類型值,壓入操作棧頂
         // 對應(yīng)代碼 x + y;
         8: iadd              // 操作數(shù)棧中的前兩個int相加,并將結(jié)果壓入操作數(shù)棧頂
         // 對應(yīng)代碼 z = x + y;
         9: istore_3          // 從棧頂彈出,并將int類型值存入局部變量表的slot_3中
         // 對應(yīng)代碼 z;
        10: iload_3           // 從局部變量表的slot_3中裝載int類型值,壓入操作棧頂
         // 對應(yīng)代碼 return z;
        11: ireturn           // 返回棧頂元素

由上可見,每次操作其實(shí)都是對棧頂或棧頂?shù)亩鄠€連續(xù)的操作棧進(jìn)行操作.方法執(zhí)行完后,會根據(jù)方法返回地址,返回上層方法,也就是上一個棧幀,如果全部棧幀都執(zhí)行完,就認(rèn)為該線程的內(nèi)容執(zhí)行完畢,線程結(jié)束生命周期.

4. 元數(shù)據(jù)區(qū) (線程共有) 也叫元空間

JDK 1.7 之前 Java虛擬機(jī)規(guī)范中定義方法區(qū)是堆的一個邏輯部分,但是別名Non-Heap(非堆),以與Java堆區(qū)分. JDK 1.8 將方法區(qū)從堆中移了出來,==放入了本地內(nèi)存==中,并且改名為==元數(shù)據(jù)區(qū)==,這是不同版本虛擬機(jī)變化最大的地方.

元數(shù)據(jù)區(qū)和堆一樣,都是線程共享的.整個虛擬機(jī)中只有一個元數(shù)據(jù)區(qū). 元數(shù)據(jù)區(qū)的大小受到本機(jī)內(nèi)存容量限制,并且允許指定大小,若不指定,元數(shù)據(jù)區(qū)會根據(jù)應(yīng)用程序運(yùn)行時的需求動態(tài)設(shè)置大小 元數(shù)據(jù)區(qū)的大小如果達(dá)到參數(shù)[MaxMetaspaceSize]設(shè)置的值,將會觸發(fā)對死亡對象和類加載器的回收.

4.1 存放內(nèi)容

元數(shù)據(jù)區(qū)中存放已經(jīng)被虛擬機(jī)加載的 :

1. 運(yùn)行時常量池
   是Class常量池的運(yùn)行時表現(xiàn)形式.
2. 字段和方法數(shù)據(jù)
3. 構(gòu)造函數(shù)和普通方法的字節(jié)碼內(nèi)容

字面量和靜態(tài)變量被移到了堆中

如下圖:

怎么用最通俗的方法講解JVM內(nèi)存模型

4.2 生命周期

元數(shù)據(jù)區(qū)其實(shí)是由一個個的類加載器存儲區(qū)組成的.當(dāng)類加載器不再存活,則該類加載器對應(yīng)的元數(shù)據(jù)區(qū)被回收.

5. 寄存器 (線程私有)

每一個線程都包含自己的寄存器,保存當(dāng)前線程執(zhí)行到了哪一行.

6. CodeCache (線程共享)

還有一部分,順帶一提 CodeCache是代碼緩存區(qū) 主要存放JIT所編譯的代碼 還有Java所使用的本地方法代碼也會存儲在codecache中. 不同的jvm、不同的啟動方式codecache的默認(rèn)值大小也不盡相同。 ==他也獨(dú)立在堆之外,是線程共享的==

JIT : 在部分商用虛擬機(jī)中(如HotSpot),Java程序最初是通過解釋器(Interpreter)進(jìn)行解釋執(zhí)行的,當(dāng)虛擬機(jī)發(fā)現(xiàn)某個方法或代碼塊的運(yùn)行特別頻繁時,就會把這些代碼認(rèn)定為“熱點(diǎn)代碼”。為了提高熱點(diǎn)代碼的執(zhí)行效率,在運(yùn)行時,虛擬機(jī)將會把這些代碼編譯成與本地平臺相關(guān)的機(jī)器碼,并進(jìn)行各種層次的優(yōu)化,完成這個任務(wù)的編譯器稱為即時編譯器.

到此

我們介紹了6個模塊,分別為:

1. PC寄存器(程序計數(shù)器)
2. 本地方法棧
3. 虛擬機(jī)棧
4. 堆
5. 元空間
6. CodeCache

那么,最開始那張圖就變成了這樣:

怎么用最通俗的方法講解JVM內(nèi)存模型

這就是Java的內(nèi)存模型了

上面說到的3個常量池

  1. 字符串常量池

  2. 運(yùn)行時常量池

  3. 類常量池

上述內(nèi)容就是怎么用最通俗的方法講解JVM內(nèi)存模型,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

jvm
AI