JVM-概述和記憶體區域

亥碼發表於2020-09-20

JVM的優勢

Java的跨平臺性

一次編譯,到處執行

JVM跨語言

舉個例子

將groovy編譯之後的class檔案用jvm執行

  1. 先配置好groovy環境

  2. 新建HelloWorld.groovy

    class HelloWorld {
       static main(args) {
          println "hello groovy...";
       }
    }
    
  3. 將其編譯成class檔案

    groovyc HelloWorld.groovy
    

  4. 用java命令執行groovy編譯出來的HelloWorld.class檔案
    (注:全域性搜尋groovy-all-xxxx.jar的jar包,將其路徑作為classpath後的引數)

    java -classpath "E:\codingEnvironment\IntelliJ IDEA 2019.1.3\lib\groovy-all-2.4.15.jar;." HelloWorld
    

JVM整體結構

HotSpot VM

  1. 方法區和堆區是所有執行緒共享的記憶體區域;

  2. Java棧又叫做jvm虛擬機器棧。

  3. 執行引擎等同於翻譯class檔案的語言翻譯器。

  4. 方法區(永久代)在jdk8中又叫做元空間

    Metaspace

    • 方法區用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即時編譯器(JIT編譯器,英文寫作Just-In-Time Compiler)編譯後的程式碼等資料。
    • 雖然Java虛擬機器規範把方法區描述為堆的一個邏輯部分,但是它卻有一個別名叫做 Non-Heap(非堆),目的應該是與 Java 堆區分開來。

執行時資料區

概述
堆記憶體:儲存所有引用資料的真實資訊;
棧記憶體:基本型別、運算、指向堆記憶體的指標;
方法區:所以定義的方法的資訊都儲存方法區中,屬於共享區;
程式計數器:是一個非常小的記憶體空間,用來保證程式依次執行;
本地方法棧:每一次執行遞迴方法的時候,都會將上一個方法入棧;

方法區(Method Area)

1. 什麼是方法區(Method Area)?

方法區(Method Area)與Java堆一樣,是各個執行緒共享的記憶體區域。

2.方法區(Method Area)儲存什麼?

它儲存已被Java虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等

域資訊(成員變數)和方法資訊可以看成在型別資訊內

2.1 類資訊

對每個載入的型別(類class、介面interface、列舉enum、註解annotation),JVM必須在方法區中儲存以下型別資訊:

  • 這個型別的完整有效名稱(全名=包名.類名)
  • 這個型別直接父類的完整有效名稱( java.lang.Object除外,其他型別若沒有宣告父類,預設父類是Object)
  • 這個型別的修飾符(public、abstract、final的某個子集)
  • 這個型別直接介面的一個有序列表
    除此之外還方法區(Method Area)儲存類資訊還有
  • 型別的常量池( constant pool)
  • 域(Field)資訊
  • 方法(Method)資訊
  • 除了常量外的所有靜態(static)變數

方法區(Method Area)儲存類資訊請參考:參考部落格

2.2 常量
  • static final修飾的成員變數都儲存於 方法區(Method Area)中
2.3 靜態變數
  • 靜態變數又稱為類變數,類中被static修飾的成員變數都是靜態變數(類變數)
  • 靜態變數之所以又稱為類變數,是因為靜態變數和類關聯在一起,隨著類的載入而存在於方法區(而不是堆中)
  • 八種基本資料型別(byte、short、int、long、float、double、char、boolean)的靜態變數會在方法區開闢空間,並將對應的值儲存在方法方法區,對於引用型別的靜態變數如果未用new關鍵字為引用型別的靜態變數分配物件(如:static Object obj;)那麼物件的引用obj會儲存在方法區中,併為其指定預設值null;若,對於引用型別的靜態變數如果用new關鍵字為引用型別的靜態變數分配物件(如:static Person person = new Person();),那麼物件的引用person 會儲存在方法區中,並且該物件在堆中的地址也會儲存在方法區中(注意此時靜態變數只儲存了物件的堆地址,而物件本身仍在堆記憶體中);這個過程還涉及到靜態變數初始化問題,可以參考部落格:靜態變數初始化相關
2.4 方法(Method)
  • 程式執行時會載入類編譯生成的位元組碼,這個過程中靜態變數(類變數)和靜態方法普通方法對應的位元組碼載入到方法區。
  • 但是!!!方法區中沒有例項變數,這是因為,類載入先於對應類物件的產生,而例項變數是和物件關聯在一起的,沒有物件就不存在例項變數,類載入時沒有物件,所以方法區中沒有例項變數
  • 靜態變數(類變數)和靜態方法普通方法在方法區(Method Area)儲存方式是有區別的

棧(Stack)

棧(Stack):執行緒私有的記憶體區域

  • 每個方法(Method)執行時,都會建立一個棧幀,用於儲存區域性變數表、運算元棧、動態連結、方法出口資訊等
  • 棧中所儲存的變數和引用都是區域性的(即:定義在方法體中的變數或者引用),區域性變數和引用都在棧中(包括final的區域性變數)
  • 八種基本資料型別(byte、short、int、long、float、double、char、boolean)的區域性變數(定義在方法體中的基本資料型別的變數)在棧中儲存的是它們對應的值
  • 棧中還儲存區域性的物件的引用(定義在方法體中的引用型別的變數)物件的引用並不是物件本身,而是物件在堆中的地址,換句話說,區域性的物件的引用所指物件在堆中的地址在儲存在了棧中。當然,如果物件的引用沒有指向具體的物件,物件的引用則是null

Java堆(Java Heap)

Java堆(Java Heap) :被所有執行緒共享的一塊記憶體區域,在虛擬機器啟動時建立。Java堆(Java Heap)唯一目的就是存放物件例項。所有的物件例項及陣列都要在Java堆(Java Heap)上分配記憶體空間。

  • 關鍵字new產生的所有物件都儲存於Java堆(Java Heap)
  • !!! 例項變數(非static修飾的成員變數)和物件關聯在一起,所以例項變數也在堆中
  • java陣列也在堆中開闢記憶體空間

棧、堆和方法區的關係

Java程式碼大致執行流程

java源程式--編譯javac-->位元組碼檔案.class-->類裝載子系統生成反射類(存入方法區)--->執行時資料區(五大塊兒)--->執行引擎-->解釋執行+編譯執行(JIT)-->作業系統(Win,Linux,Mac JVM)

作用

將高階語言轉化為機器能聽得懂的機器指令

Hotspot中方法區的變動

關於方法區的結構,在過去的版本jdk1.6/1.7/1.8當中均有變動,故在此提前宣告:

  • jdk1.6及之前:有永久代(permanent generation) ,靜態變數、字串常量池存放在 永久代上。
  • jdk1.7:有永久代,但已經逐步“去永久代”,字串常量池、靜態變數移除,儲存在堆中。注意:
  • jdk1.8及之後: 無永久代,型別資訊、欄位、方法、常量儲存在本地記憶體的元空間,但字串常量池、靜態變數仍留在堆空間.

JDK6

img

JDK7

img

注意:

jdk1.8及之後: 無永久代,型別資訊、欄位、方法、常量儲存在本地記憶體的元空間。

但字串常量池、靜態變數仍留在堆空間。

除此之外,元空間(或稱方法區),不再使用虛擬機器記憶體,而是使用本地記憶體。

JDK8

img

參考資料

JVM_01 簡介 - 傲嬌的大王 - 部落格園

(3條訊息)JVM學習筆記(三)------記憶體管理和垃圾回收_走向架構師之路-CSDN部落格

(3條訊息)Java虛擬機器(JVM)面試題(2020最新版)_ThinkWon的部落格-CSDN部落格

(4條訊息)Java方法區、棧及堆_蝸牛-CSDN部落格

Jvm垃圾回收器(終結篇) - 不二塵 - 部落格園

24個Jvm面試題總結及答案_ITPUB部落格

相關文章