【Java】JVM虛擬機內存模型

一、jvm概述

java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)

1. jvm兩種類型

  • client:GUI等java程序的運行。
  • server:大型後臺服務的運行。(重型虛擬機)

   * 兩者的區別在於: server模式下,jvm啓動較慢,但運行效率遠遠高於client模式。

* jdk在初始安裝時就會選擇安裝哪種類型,當計算機CPU最少兩顆,同時內存最少爲2GB時就會切換到server。
* 也可以手動對jvm類型進行更改,但是64位的目前只能使用server模式。
  配置文件位置:[32bit]$JAVA_HOME/jre/lib/i386/jvm.cfg  |  [64bit]$JAVA_HOME/jre/lib/amd64/jvm.cfg
  -server KNOWN
  -client KNOWN
  只需要切換兩者的順序即可,但要注意文件中不能有空行,結束必須有一個空行,否則會出錯。

jvm運行效率對比圖

2. HotSpot

  • HotSpot:熱點代碼探測技術,可以通過執行計數器找出最具有編譯價值的代碼,然後通知JIT編譯器(即時編譯系統)以方法爲單位進行編譯。如果一個方法頻繁調用,或方法中有效循環次數很多,將會觸發標準編譯和OSR(棧上替換)編譯動作。通過編譯器與解釋器恰當的協同工作,可以在最優化的程序響應時間與最佳執行性能中取得平衡,而且無需等待本地代碼輸出才能執行程序。JDK1.5版本以後纔開始使用這種策略。
  • 即時編譯JIT(Just in Time)的時間壓力也相對減小,這樣有助於引入更多的代碼優化技術,輸出質量更高的本地代碼。

二、jvm虛擬內存模型

JVM(Java Virtual Machine)包括運行時數據區(Runtime Data Areas)、執行引擎和本地方法庫。下圖是運行時數據區的圖解(圖片來源於簡書)。
在這裏插入圖片描述

  • 方法區(Method Area):方法區和堆一樣,屬於被所有線程內存共享的區域,有時候我們也會稱方法區爲非堆,用於存儲已經被Java虛擬機加載了的類信息、常量、靜態變量、以及即時編譯器編譯後的代碼等數據。

  • 運行時常量池(Runtime Constant Pool):是方法區的一部分。類文件的信息包括:類版本、字段、方法、接口等描述信息之外,還包括常量池、用於存放編譯時生成的字面量和符號引用,老版JDK中,把運行時常量池也叫永久帶,不會被GC所回收,JDK1.7之後,HotSpot虛擬機把字符串常量池從永久代中移出(String.interns()–>字符串常量池中如果包含這個對象,則返回池中的對象),可以通過改變啓動參數值-XX:PermSize和-XX:MaxPermSize設置方法區的內存大小。

  • 堆(Heap):堆是佔用Java內存最大的一塊,通常堆會佔到整個虛擬機內存的80%-85%,主要存放的是Java對象,被所有線程共享。在Java虛擬機啓動時就會被創建,幾乎所有的對象實例都會被存放在堆中,隨着JIT編譯器技術的發展和逃逸分析技術的逐漸成熟,有些對象會被分配到其他的內存區域。另外,這塊內存區域是Java虛擬機規範中唯一一塊沒有OutOfMemoryError的區域。 堆是GC(Garbage Collection)的重點回收對象,現在收集器多采用分代回收的方法,所以堆中的Java對象會進行分代,包括新生代(Young Generation)、老年代(Old Generation),老年代。新生代又分成Eden區、From Survivor區和To survivor區。 堆可以是固定的內存大小區域,也可以進行擴展。當堆無法分配對象實例並且無法進行擴展的時候,就會拋出OutOfMemoryError異常。

  • 虛擬機棧(JVM Stacks):每個方法被執行的時候都會創建一個棧幀用於存儲局部變量表,操作棧,動態鏈接,方法出口等信息。每一個方法被調用的過程就對應一個棧幀在虛擬機棧中從入棧到出棧的過程。其中局部變量表存放的是編譯器可知的基本數據類型和return Address類型。long和double類型會佔用兩個slot空間(局部變量空間),其餘數據類型只佔用1個,局部變量表內存空間在編譯期間完成分配,運行期間,局部變量表的內存空間不會再發生改變。

  • 本地方法棧(Native Method Stacks):和虛擬機棧所發揮的作用很類似,區別不同的是,本地方法棧執行的Java的本地方法(native)方法,而虛擬機棧執行的是Java方法(編譯成字節碼的方法)。有時候虛擬機會將這兩個棧合二爲一,本地方法棧和虛擬機棧都會出現StackOverFlowError(超過棧深度)和OutOfMemoryError(動態擴展內存不足)。

  • 程序計數器(Program Counter Register):是一塊很小的內存區域,線程私有的,記錄的是線程執行的字節碼的行號。分支、循環、跳轉、異常、線程恢復都需要依賴於程序計數器。當執行的程序是Java的底層(native)方法時,程序計數器爲空,如果執行的是Java方法,計數器記錄的是虛擬機字節碼指令的地址。這塊內存區域是Java虛擬機規範中唯一一塊沒有OutOfMemoryError的區域。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章