java 堆(heap)、棧(stack)和方法區(method)

JAVA的JVM的內存可分爲3個區:堆(heap)、棧(stack)和方法區(method)
堆區:
1.存儲的是new出來的對象和數組,每個對象都包含一個與之對應的class的信息。(class的目的是得到操作指令)
2.jvm只有一個堆區(heap)被所有線程共享,堆中不存放基本類型和對象引用,只存放對象本身
棧區:
1.每個線程包含一個棧區,棧中保存的是所有的變量,包括基本類型和引用類型,棧中的每個變量都包含類型、名稱、值這些內容,只不過基本類型變量的值爲一個具體的值,而引用類型的變量的值爲對象在堆中的地址。
2.每個棧中的數據(原始類型和對象引用)都是私有的,其他棧不能訪問。
3.棧分爲3個部分:基本類型變量區、執行環境上下文、操作指令區(存放操作指令)。
方法區:
1.又叫靜態區,跟堆一樣,被所有的線程共享。方法區包含所有的class和static變量。

2.方法區中包含的都是在整個程序中永遠唯一的元素,如class,static變量。

3.字符串常量池就是存放在方法區。(具體原因參見:http://zangxt.iteye.com/blog/472236)


堆和棧的不同:

<1>存數數據不同

<2>回收方式不同

棧中當超過變量的作用域後,java會自動釋放掉爲該變量分配的內存空間,該內存空間可以立刻被另作他用。

數組和對象在沒有引用變量指向它的時候,才變成垃圾,不能再被使用,但是仍然佔着內存,在隨後的一個不確定的時間被垃圾回收器釋放掉。

<3>速度不同

堆中分配的內存,由Java虛擬機的自動垃圾回收器來管理。

堆和棧的優缺點:

<1>堆的優勢是可以動態地分配內存大小,生存期也不必事先告訴編譯器,因爲它是在運行時動態分配內存的,Java的垃圾收集器會自動收走這些不再使用的數據。但缺點是,由於要在運行時動態分配內存,存取速度較慢.

<2>棧的優勢是,存取速度比堆要快,僅次於寄存器,棧數據可以共享。但缺點是,存在棧中的數據大小與生存期必須是確定的,缺乏靈活性

舉例: int a = 3;  int b = 3; 

編譯器先處理int a = 3;首先它會在棧中創建一個變量爲a的引用,然後查找棧中是否有3這個值,如果沒找到,就將3存放進來,然後將a指向3。
接着處理int b = 3;在創建完b的引用變量後,因爲在棧中已經有3這個值,便將b直接指向3。這樣,就出現了a與b同時均指向3的情況。
這時,如果再令a=4;那麼編譯器會重新搜索棧中是否有4值,如果沒有,則將4存放進來,並令a指向4;如果已經有了,則直接將a指向這個地址。
因此a值的改變不會影響到b的值。

 

簡單代碼語句的執行過程:

系統收到了我們發出的指令,啓動了一個Java虛擬機進程,這個進程首先從classpath中找到AppMain.class文件,讀取這個文件中的二進制數據,
然後把Appmain類的類信息存放到運行時數據區的方法區中。這一過程稱爲AppMain類的加載過程。
接着,Java虛擬機定位到方法區中AppMain類的Main()方法的字節碼,開始執行它的指令。這個main()方法的第一條語句就是:
Sample test1=new Sample("測試1");
就是讓java虛擬機創建一個Sample實例,並且呢,使引用變量test1引用這個實例。就讓我們來跟蹤一下Java虛擬機,看看它究竟是怎麼來執行這個任務的:
1、 Java虛擬機直奔方法區,先找到Sample類的類型信息。結果這會兒的方法區裏還沒有Sample類。於是立馬加載了Sample類,把Sample類的類型信息存放在方法區裏。
2、 爲一個新的Sample實例分配內存, 這個Sample實例持有着指向方法區的Sample類的類型信息的引用。而這個引用地址,就存放了在Sample實例的數據區裏。
3、 在JAVA虛擬機進程中,每個線程都會擁有一個方法調用棧,用來跟蹤線程運行中一系列的方法調用過程,棧中的每一個元素就被稱爲棧幀,每當線程調用一個方法的時候就會向方法棧壓入一個新幀。這裏的幀用來存儲方法的參數、局部變量和運算過程中的臨時數據。OK,原理講完了,就讓我們來繼續我們的跟蹤行動!位於“=”前的Test1是一個在main()方法中定義的變量,可見,它是一個局部變量,因此,它被會添加到了執行main()方法的主線程的JAVA方法調用棧中。而“=”將把這個test1變量指向堆區中的Sample實例,也就是說,它持有指向Sample實例的引用。

接下來,JAVA虛擬機將繼續執行後續指令,在堆區裏繼續創建另一個Sample實例,然後依次執行它們的printName()方法。當JAVA虛擬機執行test1.printName()方法時,JAVA虛擬機根據局部變量test1持有的引用,定位到堆區中的Sample實例,再根據Sample實例持有的引用,定位到方法去中Sample類的類型信息,從而獲得printName()方法的字節碼,接着執行printName()方法包含的指令。

發佈了6 篇原創文章 · 獲贊 8 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章