1. 程式人生 > >Java方法區、棧及堆

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 
版權宣告:本文為博主原創文章,轉載請附上博文連結!