1. 程式人生 > >Java JVM 中 堆,棧,方法區 詳解

Java JVM 中 堆,棧,方法區 詳解

一 jvm執行時資料區有哪些

我們先來看一張圖
這裡寫圖片描述
JVM執行時資料區分類
1. JVM棧 (Java Virtual Machine Stacks)
2. 堆記憶體 (Heap Memory)
3. 方法區 (Method Area)
4. 本地方法棧 (Native Method Stacks)
5. 程式計數器 (Program Counter (PC) Register)

二 詳解資料區

2.1 JVM棧 (Java Virtual Machine Stacks)

在介紹JVM棧之前,我先了解一下 棧幀 概念
棧幀:一個棧幀隨著一個方法的呼叫開始而建立,這個方法呼叫完成而銷燬。棧幀記憶體放者方法中的區域性變數,運算元棧等資料。

Java棧也稱作虛擬機器棧(Java Vitual Machine Stack),JVM棧只對棧幀進行儲存,壓棧和出棧操作。Java棧是Java方法執行的記憶體模型。下面我們來看一個Java棧圖。

這裡寫圖片描述

由上圖可以看出,Java棧中存放的是一個個的棧幀,每個棧幀對應一個被呼叫的方法,在棧幀中包括區域性變量表(Local Variables)、運算元棧(Operand Stack)、指向當前方法所屬的類的執行時常量池(執行時常量池的概念在方法區部分會談到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些額外的附加資訊。當執行緒執行一個方法時,就會隨之建立一個對應的棧幀,並將建立的棧幀壓棧。當方法執行完畢之後,便會將棧幀出棧。因此可知,執行緒當前執行的方法所對應的棧幀必定位於Java棧的頂部。對於所有的程式設計語言來說,棧這部分空間對程式設計師來說是不透明的。

棧記憶體的大小可以有兩種設定,固定值和根據執行緒需要動態增長。
在JVM棧這個資料區可能會發生丟擲兩種錯誤。
1. StackOverflowError 出現在棧記憶體設定成固定值的時候,當程式執行需要的棧記憶體超過設定的固定值會丟擲這個錯誤。
2. OutOfMemoryError 出現在棧記憶體設定成動態增長的時候,當JVM嘗試申請的記憶體大小超過了其可用記憶體時會丟擲這個錯誤。

總結
1. 每個執行緒包含一個棧區,棧中只儲存基礎資料型別的物件和自定義物件的引用(不是物件)。物件都存放在堆區中。
2. 每個戰中的資料(基礎資料型別和物件引用)都是私有的,其他棧不能訪問。
3. 棧分為3個部分:基本型別變數,執行環境上下文,操作指令區(存放操作指令).
4. 在函式中定義的一些基本型別的變數資料和物件的引用變數都在函式的棧記憶體中分配。
5. 當在一段程式碼塊定義一個變數時,Java就在棧中為這個變數分配記憶體空間,當該變數退出該作用域後,Java會自動釋放掉為該變數所分配的記憶體空間,該記憶體空間可以立即被另作他用。

2.2 堆記憶體 (Heap Memory)

堆資料區是用來存放物件和陣列(特殊的物件)。堆記憶體由多個執行緒共享。堆記憶體隨著JVM啟動而建立。眾所周知,Java中有一個很好的特性就是自動垃圾回收。垃圾回收就操作這個資料區來回收物件進而釋放記憶體。如果堆記憶體剩餘的記憶體不足以滿足於物件建立,JVM會丟擲OutOfMemoryError錯誤。

總結
1. 儲存的全部是物件,每個物件包含一個與之對應的class資訊–class的目的是得到操作指令。
2. jvm只有一個堆區(heap)被所有執行緒共享,堆區中不存放基本型別和物件引用,只存放物件本身。
3. 堆的優勢是可以動態地分配記憶體大小,生存期也不必事先告訴編譯器,因為它是在執行時動態分配記憶體的,Java的垃圾收集器會自動收走這些不再使用的資料。
4. 缺點是,由於要在執行時動態分配記憶體,存取速度較慢。

2.3方法區 (Method Area)

方法區在JVM中也是一個非常重要的區域,它與堆一樣,是被執行緒共享的區域。在方法區中,儲存了每個類的資訊(包括類的名稱、方法資訊、欄位資訊)、靜態變數、常量以及編譯器編譯後的程式碼等。

在Class檔案中除了類的欄位、方法、介面等描述資訊外,還有一項資訊是常量池,用來儲存編譯期間生成的字面量和符號引用。

在方法區中有一個非常重要的部分就是執行時常量池,它是每一個類或介面的常量池的執行時表示形式,在類和介面被載入到JVM後,對應的執行時常量池就被創建出來。當然並非Class檔案常量池中的內容才能進入執行時常量池,在執行期間也可將新的常量放入執行時常量池中,比如String的intern方法。

2.4本地方法棧 (Native Method Stacks)

一個支援native方法呼叫的JVM實現,需要有這樣一個數據區,就是本地方法棧,Java官方對於本地方法的定義為methods written in a language other than the Java programming language,就是使用非Java語言實現的方法,但是通常我們指的一般為C或者C++,因此這個棧也有著C棧這一稱號。一個不支援本地方法執行的JVM沒有必要實現這個資料區域。本地方法棧基本和JVM棧一樣,其大小也是可以設定為固定值或者動態增加,因此也會對應丟擲StackOverflowError和OutOfMemoryError錯誤。
在HotSopt虛擬機器中直接就把本地方法棧和Java棧合二為一。

2.5 程式計數器 (Program Counter (PC) Register)

在通用的計算機體系中,程式計數器用來記錄當前正在執行的指令,在JVM中也是如此。程式計數器是執行緒私有,所以當一個新的執行緒建立時,程式計數器也會建立。由於Java是支援多執行緒,Java中的程式計數器用來記錄當前執行緒中正在執行的指令。如果當前正在執行的方法是本地方法,那麼此刻程式計數器的值為undefined。注意這個區域是唯一一個不丟擲OutOfMemoryError的執行時資料區。