1. 程式人生 > >一、基礎篇(JVM記憶體結構)

一、基礎篇(JVM記憶體結構)

一.概念

JAVA的JVM的記憶體可分為3個區:堆(heap)、棧(stack)和方法區(method)

1)堆區:

a.儲存的全部是物件,每個物件都包含一個與之對應的class的資訊。(class的目的是得到操作指令)

b.jvm只有一個堆區(heap)被所有執行緒共享,堆中不存放基本型別和物件引用,只存放物件本身

2)棧區:

a.每個執行緒包含一個棧區,棧中只儲存基礎資料型別的物件和自定義物件的引用(不是物件),物件都存放在堆區中

b.每個棧中的資料(原始型別和物件引用)都是私有的,其他棧不能訪問。

c.棧分為3個部分:基本型別變數區、執行環境上下文、操作指令區(存放操作指令)。

3)方法區:

a.又叫靜態區,跟堆一樣,被所有的執行緒共享。方法區包含所有的class和static變數。

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

二.案例解析

Test.java

//執行時, jvm 把Test的資訊都放入方法區
public class Test {

	/**
	 * @Description: main方法
	 * @param @param args   
	 * @return void  
	 * @throws
	 * @date 2018-11-27 下午2:01:23
	 */
	public static void main(String[] args) { //main 方法本身放入方法區。
		MyObject test1=new MyObject("測試1");
		test1.printName();
	}

}

MyObject.java

//執行時, jvm 把MyObject的資訊都放入方法區
public class MyObject {
	/*範例名稱 */ 
	private String name;//new MyObject例項後, name 引用放入棧區裡,  name 物件放入堆裡
	/*構造方法 */ 
	public MyObject(String name){
		this .name = name;
	}
	/*輸出方法*/ 
	public void printName(){//printName方法本身放入 方法區裡。
		System.out.println(name);
	}
}

跟著Test程式碼走一遍(圖示):

1)載入Test類:

首先執行指令:“java Test”,系統收到發出的指令,啟動一個Java虛擬機器程序,這個程序首先從classpath中找到Test.class檔案,讀取這個檔案中的二進位制資料,然後把Test類的類資訊存放到執行時資料區的方法區中。

2)執行main()方法:

Java虛擬機器定位到方法區中Test類的main()方法的位元組碼,開始執行它的指令。這個main()方法的第一條語句就是:MyObject test1=new MyObject("測試1")。就是讓java虛擬機器建立一個MyObject 例項,並且使引用變數test1引用這個例項。

具體過程:

a.建立一個MyObject 例項,去方法區先找到MyObject 類的型別資訊。首次沒找到,方法區裡還沒有MyObject 類。所以Java虛擬機器立即載入了MyObject 類,把MyObject 類的型別資訊存放在方法區裡。

b.Java虛擬機器首先在堆區中為一個新的MyObject 例項分配記憶體, 這個MyObject 例項持有著指向方法區的MyObject 類的型別資訊的引用。這裡所說的引用,實際上指的是MyObject 類的型別資訊在方法區中的記憶體地址,而這個地址就存放了在MyObject 例項的資料區裡。

c.在JAVA虛擬機器程序中,每個執行緒都會擁有一個方法呼叫棧,用來跟蹤執行緒執行中一系列的方法呼叫過程,棧中的每一個元素就被稱為棧幀,每當執行緒呼叫一個方法的時候就會向方法棧壓入一個新幀。這裡的幀用來儲存方法的引數、區域性變數和運算過程中的臨時資料。

d.位於“=”前的test1是一個在main()方法中定義的變數,它是一個區域性變數,它被會新增到了執行main()方法的主執行緒的JAVA方法呼叫棧中。而“=”將把這個test1變數指向堆區中的MyObject 例項,它持有指向MyObject 例項的引用。

e.JAVA虛擬機器將繼續執行後續指令,執行test1的printName()方法,當JAVA虛擬機器執行test1.printName()方法時,JAVA虛擬機器根據區域性變數test1持有的引用,定位到堆區中的MyObject 例項,再根據MyObject 例項持有的引用,定位到方法去中MyObject 類的型別資訊,從而獲得printName()方法的位元組碼,接著執行printName()方法包含的指令。