JVM的特性,透過程式碼來揭秘執行時資料區

程式設計師的成長之路發表於2018-11-29

執行時資料區

之前學習類載入器的時候,最後放出了一張圖,再來回顧一下

JVM的特性,透過程式碼來揭秘執行時資料區

類載入器就是把位元組碼檔案載入到執行時資料區裡面的一個機制,載入到執行時資料區之後呢,又發生了什麼?

接下來我們就來看看。這就是JVM執行時資料區:

JVM的特性,透過程式碼來揭秘執行時資料區

執行時資料區分為:方法去、堆、虛擬機器棧、本地方法棧、程式計數器。

而黃色區,會被稱為棧。

堆和棧的根本作用,就是用來存放資料用的。

先上一段程式碼:

/**  * 作者:LKP  * 時間:2018/11/7  */
class Person{     String name = new String("1234");    
     public Person(String name) {        
         this.name = name;     }    
     public void sayHello(){         System.out.println("hello:"+name);     } }
public class AppTest {    
   public static void main(String[] args) {        Person person = new Person("張三");        person.sayHello();    }  }
後面的分析都是建立在這個AppTest類的。

堆:

堆是用來幹嘛的?

JVM的特性,透過程式碼來揭秘執行時資料區

就好比前面的程式,new Person("張三"); 它儲存的地方就是在堆裡面。

什麼是OutOfMemoryError異常,可能有些人沒有接觸過,我也是再一次面試當中遇到的,之後去查閱過相關資料。

現在我們來模擬一下OutOfMemoryError異常:

/**  * 作者:LKP  * 時間:2018/11/7  */
public class HeapOOM {    
  //-Xms64m -Xmx128m    public static void main(String[] args) {        String[] str = new String[400000000];        System.out.println(str.length);    } }

啟動引數設定為:-Xms64m -Xmx128m,然後執行:

JVM的特性,透過程式碼來揭秘執行時資料區

這種異常就是OutOfMemoryError異常,記憶體溢位了,造成的原因很多種,有興趣的小夥伴可以去了解一下。

方法區:

之前說到了類載入載入,並且執行,我們怎麼樣執行呢?這就跟方法區有關係了。

JVM的特性,透過程式碼來揭秘執行時資料區

類資訊:它是對一個類的描述

JVM的特性,透過程式碼來揭秘執行時資料區

上面兩條sql語句一樣,第一條是它的表結構,這些就是表結構的資訊。類資訊(MetaInfo)就是後設資料,描述我們一個類的資訊的。

執行時常量池:它的作用是存放我們一些常量和靜態變數的

比如:

靜態變數:static int NAME = "張三";

常量:final .....

這些都是存放在執行時常量池的。

編譯器有兩個:一個是靜態編譯,一個是JIT。

JIT編譯:就是執行編譯。

靜態編譯:java編譯成class檔案

為什麼要有JIT編譯呢?那肯定是有它好處的:

JVM的特性,透過程式碼來揭秘執行時資料區

看一下這段程式碼,他是熱點程式碼,就是需要頻繁去執行的

為了效率,JIT編譯會把位元組碼編譯為機器執行碼,這樣速度就大大提高了。

JIT的目的,就是把位元組碼>>>機器執行碼,把它存放在方法區裡面。

方法區呢,就是存放方法的地方,不過為了區分不同類的方法,也需要把類資訊也儲存進去,這樣才能區分不同類的相同方法。

程式計數器:

什麼是程式計數器?

JVM的特性,透過程式碼來揭秘執行時資料區

程式計數器它就是讓我們程式按照我們的指定指令執行的步驟,我們的步驟放到一個區域裡面,程式計數器就按照第一步幹什麼,第二步幹什麼來執行。

棧:

什麼是棧呢?先看看這張圖

JVM的特性,透過程式碼來揭秘執行時資料區

為了更好的進行理解,我們先來寫個遞迴:

/**  * 作者:LKP  * 時間:2018/11/8  */
public class Digui {    
   private Long i = 0l;    
   public void test(int a, double d) {        i++;        System.out.println("=====>" + i);        test(a, d);    }    
   public static void main(String[] args) {        Digui app = new Digui();        app.test(0, 0.0d);    }  }
執行一下:

JVM的特性,透過程式碼來揭秘執行時資料區

JVM的特性,透過程式碼來揭秘執行時資料區

報錯了(StackOverflowError)。為什麼報錯呢?

StackOverflowError異常代表的是,當棧深度超過虛擬機器分配給執行緒的棧大小時就會出現此error。

所以棧和程式執行有關:

JVM的特性,透過程式碼來揭秘執行時資料區

棧概念:先進後去的原則,剛剛出現StackOverflowError的異常,證明棧是有數量限制的。

每個棧幀裡面儲存的又是什麼呢?

JVM的特性,透過程式碼來揭秘執行時資料區

區域性變數表又是什麼?

JVM的特性,透過程式碼來揭秘執行時資料區

main函式一般都是主執行緒,步驟1產生的就是區域性變數表。

那為什麼又要壓棧呢?

看一下步驟2,因為當執行main執行緒的時候,add執行緒還沒有產生。當執行add的時候會把它放在main上面,為什麼這樣,這就和等下彈棧有關係了。

步驟2返回C就是最關鍵的,它就是彈棧過程,彈出的這個資料機構(add執行緒)就消失了,什麼都沒有了,包括區域性變數什麼的。

步驟3是返回到main執行緒去了。

為什麼用棧不用佇列呢?原因很簡答,因為彈棧壓棧都是最簡單的,而佇列則需要去查詢。

來看看JVM中堆、棧和方法區這三者的聯絡。

JVM的特性,透過程式碼來揭秘執行時資料區

區域性變數表可以存放八大資料基本型別,再加上一種引用reference(引用就是一個地址,指向堆、常量池的地址)

回顧一開始出現的程式,結合來理解這三者的關係。

JVM的特性,透過程式碼來揭秘執行時資料區

看完這篇文章,相信你對資料執行區的瞭解加深了很多。

最後再來看一下JVM記憶體區域:

JVM的特性,透過程式碼來揭秘執行時資料區

1.8 永久代已經廢掉了,直接使用記憶體,不過多闡述,有興趣可自行去了解。

JVM的特性,透過程式碼來揭秘執行時資料區


有什麼錯誤,或者用詞不當還希望大家留言。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69900357/viewspace-2222087/,如需轉載,請註明出處,否則將追究法律責任。

相關文章