黑莲技术资源论坛

作者: wuwuqiwu
查看: 98|回复: 0

JVM內存模型和結構詳解(五大模型圖解)

JVM內存模型和結構詳解(五大模型圖解)

[复制链接]
wuwuqiwu | 显示全部楼层 发表于: 2022-8-5 08:23:58
wuwuqiwu 发表于: 2022-8-5 08:23:58 | 显示全部楼层 |阅读模式
查看: 98|回复: 0

JVM內存模型和Java內存模型都是大廠面試的熱點問題,名字看感覺都差不多,實際上他們之間差別還是挺大的。
通俗點說,JVM內存模型是與JVM的內部存儲結構相關,而Java內存模型是與多線程並發編程相關@mikechen
今天主要講解JVM內存模型相關的8點內容︰

  • 為什麼需要JVM?
  • JVM內存模型
  • 堆(Heap)
  • 方法區(Method Area)
  • 虛擬機棧(JVM Stack)
  • 本地方法棧(Native Stack)
  • 程序計數器(PC Register)
  • JVM內存模型小結


為什麼需要JVM?

JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一個虛構出來的計算機,有著自己完善的硬件架構,如處理器、堆棧等。


Java語言使用Java虛擬機屏蔽了與具體平台相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平台上不加修改地運行。
Java文件必須先通過一個叫javac的編譯器,將代碼編譯成class文件,然後通過JVM把class文件解釋成各個平台可以識別的機器碼,最終實現跨平台運行代碼。


JVM內存模型

JVM內存模型可以分為兩個部分,如下圖所示,堆和方法區是所有線程共有的,而虛擬機棧,本地方法棧和程序計數器則是線程私有的。


在JVM1.8中,圖中的 方法區為元數據區,下面展開談一談這五個區域的作用。
堆(Heap)

在 Java 中,堆被劃分成兩個不同的區域︰新生代 ( Young )、老年代 ( Old ),新生代 ( Young ) 又被劃分為三個區域︰Eden、From Survivor、To Survivor。
下圖中的Perm代表的是永久代,但是注意永久代並不屬于堆內存中的一部分,同時jdk1.8之後永久代也將被移除。


堆是java虛擬機所管理的內存中最大的一塊內存區域,也是被各個線程共享的內存區域,該內存區域存放了對象實例及數組(但不是所有的對象實例都在堆中)。
其大小通過-Xms(最小值)和-Xmx(最大值)參數設置,前者為啟動時申請的最小內存,默認為操作系統物理內存的1/64,後者為JVM可申請的最大內存,默認為物理內存的1/4,默認當空余堆內存小于40%時,JVM會增大堆內存到-Xmx指定的大小,可通過-XX:MinHeapFreeRation=來指定這個比列。
當空余堆內存大于70%時,JVM會減小堆內存的大小到-Xms指定的大小,可通過XX:MaxHeapFreeRation=來指定這個比列,當然為了避免在運行時頻繁調整Heap的大小,通常-Xms與-Xmx的值設成一樣。堆內存 = 新生代+老生代+持久代。
在我們垃圾回收的時候,我們往往將堆內存分成新生代和老生代(大小比例1︰2),新生代中由Eden和Survivor0,Survivor1組成,三者的比例是8︰1︰1,新生代的回收機制采用復制算法,在Minor GC的時候,我們都留一個存活區用來存放存活的對象,真正進行的區域是Eden+其中一個存活區,當我們的對象時長超過一定年齡時(默認15,可以通過參數設置),將會把對象放入老生代,當然大的對象會直接進入老生代,老生代采用的回收算法是標記整理算法。


方法區(Method Area)

其實方法區是在JDK1.8以前的版本里存在的一塊內存區域,主要就是存放從class文件里加載進來的類的,而且常量池也是在這塊區域內的。
但是在JDK1.8之後,這塊區域搖身一變,換了名字,叫做“Metaspace”,翻譯過來就是“元數據空間”的意思,當然它只是改了個名,實現的功能是沒變的。
方法區(Method Area)與Java堆一樣,是各個線程共享的內存區域,它用于存儲已被虛擬機加載的類型信息、常量、靜態變量、即時編譯器編譯後的代碼緩存等數據。


1.類型信息
對每個加載的類型(類class、接口interface、枚舉enum、注解annotation),JVM必須在方法區中存儲以下類型信息:
這個類型的完整有效名稱(全名=包名.類名)
這個類型直接父類的完整有效名(對于interface或是java.lang.0bject,都沒有父類)
這個類型的修飾符(public, abstract,final的某個子集)
這個類型直接接口的一個有序列表
2.域信息(Field)成員變量
JVM必須在方法區中保存類型的所有域的相關信息以及域的聲明順序。
域的相關信息包括:域名稱、域類型、域修飾符(public, private,protected,static,final, volatile, transient的某個子集)
3.方法(Method)信息
JVM必須保存所有方法的以下信息,同域信息一樣包括聲明順序:

  • 方法名稱
  • 方法的返回類型(或void)€€方法參數的數量和類型(按順序)
  • 方法的修飾符(public, private,protected,static, final,synchronized,native,abstract的一個子集)
  • 方法的字節碼(bytecodes)、操作數棧、局部變量表及大小(abstract和native方法除外)


虛擬機棧(JVM Stack)

虛擬機棧(Java Virtual Machine Stack),早期也叫Java棧,每個線程在創建時都會創建一個虛擬機棧,其內部保存一個個的棧幀(Stack Frame),對應著一次次的Java方法調用。
虛擬機棧的作用︰主管Java程序的運行,它保存方法的局部變量、部分結果,並參與方法的調用和返回。
每個方法被執行的時候都會創建一個”棧幀”,用于存儲局部變量表(包括參數)、操作棧、方法出口等信息。
每個方法被調用到執行完的過程,就對應著一個棧幀在虛擬機棧中從入棧到出棧的過程。
棧幀(Stack Frame) 是用于虛擬機執行時方法調用和方法執行時的數據結構,它是虛擬棧的基本元素,棧幀由局部變量區、操作數棧等組成,如下圖所示︰


每一個方法從調用到方法返回都對應著一個棧幀入棧出棧的過程。
最頂部的棧幀稱為當前棧幀,棧幀所關聯的方法稱為當前方法,定義這個方法的類稱為當前類,該線程中,虛擬機有且也只會對當前棧幀進行操作。
棧幀的作用有存儲數據,部分過程結果,處理動態鏈接,方法返回值和異常分派。
每一個棧幀包含的內容有局部變量表、操作數棧、動態鏈接、方法返回地址和一些額外的附加信息。


本地方法棧(Native Stack)

本地方法棧(Native Method Stacks)與虛擬機棧所發揮的作用是非常相似的,其區別不過是虛擬機棧為虛擬機執行Java 方法(也就是字節碼)服務,而本地方法棧則是為虛擬機使用到的Native 方法服務。
虛擬機規範中對本地方法棧中的方法使用的語言、使用方式與數據結構並沒有強制規定,因此具體的虛擬機可以自由實現它。
甚至有的虛擬機(譬如Sun HotSpot 虛擬機)直接就把本地方法棧和虛擬機棧合二為一。


程序計數器(PC Register)

在JVM的概念模型里,字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令。
分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴這個計數器來完成。
JVM的多線程是通過線程輪流切換並分配處理器執行時間的方式來實現的,為了各條線程之間的切換後計數器能恢復到正確的執行位置,所以每條線程都會有一個獨立的程序計數器。
當線程正在執行一個Java方法,程序計數器記錄的是正在執行的JVM字節碼指令的地址,如果正在執行的是一個Natvie(本地方法),那麼這個計數器的值則為空(Underfined)。


JVM內存模型小結

本篇介紹了JVM虛擬機中運行時數據區的五個內存區域︰堆、方法區、虛擬機棧、本地方法棧、程序計數器,這些地方也是我們平時開發中最常接觸到的地方,所以對其有所掌握了解還是很有必要的,也有助于JVM問題排查!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|小黑屋|黑莲技术资源论坛 ( 闽ICP备18016623号-7 )|网站地图

GMT+8, 2022-8-19 04:43 , Processed in 0.633456 second(s), 26 queries .

Powered by BBS.HL1.NET X3.4 © 2020-2022

本站IT社区(bbs.hl1.net)所有的资源教程均来自网友分享及互联网收集

快速回复 返回顶部 返回列表