Java方法區、棧及堆
Java方法區、棧及堆
一 方法區(Method Area)
1. 什麼是方法區(Method Area)?
《深入理解JVM》書中對方法區(Method Area)描述如下:
方法區(Method Area)與Java堆一樣,是各個執行緒共享的記憶體區域。
2.方法區(Method Area)儲存什麼?
《深入理解JVM》書中對方法區(Method Area)儲存內容描述如下:
它儲存已被Java虛擬機器載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等
2.1 方法區(Method Area)儲存的類資訊
對每個載入的型別(類class、介面interface、列舉enum、註解annotation),JVM必須在方法區中儲存以下型別資訊:
這個型別的完整有效名稱(全名=包名.類名)
這個型別直接父類的完整有效名稱( java.lang.Object除外,其他型別若沒有宣告父類,預設父類是Object)
這個型別的修飾符(public、abstract、final的某個子集)
這個型別直接介面的一個有序列表
除此之外還方法區(Method Area)儲存類資訊還有
型別的常量池( constant pool)
域(Field)資訊
方法(Method)資訊
除了常量外的所有靜態(static)變數
方法區(Method Area)儲存類資訊請參考:參考部落格
2.2 方法區(Method Area)儲存的常量
static final修飾的成員變數都儲存於 方法區(Method Area)中
2.3 方法區(Method Area)儲存的靜態變數
靜態變數又稱為類變數,類中被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 Area)儲存的方法(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陣列也在堆中開闢記憶體空間
四 示例
public class PersonDemo
{
public static void main(String[] args)
{ //區域性變數p和形參args都在main方法的棧幀中
//new Person()物件在堆中分配空間
Person p = new Person();
//sum在棧中,new int[10]在堆中分配空間
int[] sum = new int[10];
}
}
class Person
{ //例項變數name和age在堆(Heap)中分配空間
private String name;
private int age;
//類變數(引用型別)name1和"cn"都在方法區(Method Area)
private static String name1 = "cn";
//類變數(引用型別)name2在方法區(Method Area)
//new String("cn")物件在堆(Heap)中分配空間
private static String name2 = new String("cn");
//num在堆中,new int[10]也在堆中
private int[] num = new int[10];
Person(String name,int age)
{
//this及形參name、age在構造方法被呼叫時
//會在構造方法的棧幀中開闢空間
this.name = name;
this.age = age;
}
//setName()方法在方法區中
public void setName(String name)
{
this.name = name;
}
//speak()方法在方法區中
public void speak()
{
System.out.println(this.name+"..."+this.age);
}
//showCountry()方法在方法區中
public static void showCountry()
{
System.out.println("country="+country);
}
}
---------------------
作者:zhiman
來源:CSDN
原文:https://blog.csdn.net/u013241673/article/details/78574770
版權宣告:本文為博主原創文章,轉載請附上博文連結!