【Java】JVM內存模型解析

 

 JVM內存模型主要分爲五大區域:棧、堆、本地方法棧、程序計數器、方法區。

 

本地方法棧:

跟虛擬機棧非常相似,也是線程私有的,不過虛擬機棧是針對Java方法,而本地方法棧是針對native方法,也就是底層方法。

由於Java是跨平臺語言,導致的它不得不犧牲一些對底層方法的控制,而要實現這些底層方法的控制,就需要用到native方法,而本地方法棧就是針對native方法的。

程序計數器:

每一個線程內部都有自己的程序計數器,是相互獨立的,保證每個線程的程序運行不會出錯,因此程序計數器是線程私有的。

在idea將Java代碼運行時都會被轉譯成字節碼文件,字節碼文件是二進制文件,識別起來比較困難,所以在編譯時用到計數器,爲編譯好的字節碼添加行號,後期調用的時候就能按順序分條執行。記錄程序運行的位置。

虛擬機棧:

線程私有的,生命週期和線程相同,它描述的是Java方法執行的內存模型,每一個虛擬機棧都有自己的棧針,每一個方法的執行都是入棧和出棧的過程(想到關於棧和隊列的區別,有一個形象的例子,隊列是先進先出 吃了拉,棧是先進後出 吃了吐 ),每一個棧中都有着局部變量表和操作數棧,局部變量表是變量值的存儲空間,用於存放方法參數和方法內部定義的局部變量,操作數棧存儲的數據與局部變量表一致,是通過彈棧和壓棧來進行訪問的,操作數棧可以理解爲Java虛擬機棧中的一個用於計算的臨時數據存儲區。(Java的基本數據類型大部分都是存儲在棧的,除了一些引用變量和引用類型。String不是基本據類型!基本數據類型就只有八個,數值型:byte,short,int,long,浮點型:float,double,字符型:char,布爾型:boolean。

方法區:

也叫永久區,jdk8以後叫元數據區,是線程共享,裏面存儲着被虛擬機加載的類信息,常量,靜態變量

程序執行時,將字節碼文件加載到方法區的常量池,存儲一些和類有關的屬性,方法區的清理也是通過垃圾回收,回收目標主要是常量池中廢棄的常量和不再使用的類型。

 堆:

堆區用於存放所有new出來的對象和數組,是線程共享的,堆區中的對象和棧區中的對象往往是成對出現的,一般的程序是通過棧區的對象引用來訪問堆區的對象,因爲是共享的,意味着對個對象引用可以指向同一個對象,在沒有引用變量的指向時,就會變成垃圾,不被使用,被垃圾回收機制清理。

 

看一下代碼的執行結果。

 public static void main(String[] args) {
        ArrayList<String> a = null;
        test(a);
        System.out.println(a.size());
    }

    public static void test(ArrayList<String> a){
        a = new ArrayList<>();
        a.add("a");
    }

執行後會返回什麼?打印出1嗎?

結果顯然不是,會在 System.out.println(a.size()); 時拋出空指針異常。

 

我們分析下程序執行的內存模型。

首先定義了一個ArrayList類型的a變量,a是一個指針,不過現在指向的是null。

調用了test方法,傳入形參a,實際上傳的是a的副本。

在靜態方法test中,new了一個arrayList,在堆中開闢了空間存儲了new的對象,將a指向堆中new出來對象的地址。

然後執行 a.add("a"); 

test方法結束,銷燬test方法執行時產生的局部變量。

回到main方法中,打印a.size時的a還是之前聲明的指向null的變量。故拋出空指針異常。

 

https://www.bilibili.com/video/BV12t411u726?from=search&seid=1631061805620865620

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