java虛擬機內存管理
每個線程就是一個順序的執行單元,線程共享區即多個線程共享同一塊區域,線程獨占區即每個線程都有自己的虛擬機棧,本地方法棧,程序計數器。
程序計數器是一個比較小的內存空間,可以看作是當前線程所執行的字節碼的行號指示器,位于線程獨占區,如果線程執行的是java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址,如果執行的是native方法,計數器的值為underfined
Java虛擬機棧
虛擬機描述的是java方法執行的動態內存模型
棧幀
每個方法執行,都會創建一個棧幀,伴隨著方法從創建到執行完成,用于存儲變量表,操作數棧,動態鏈接,方法出口等。
局部變量表
存儲編譯期可知的各種基本數據類型,引用類型,returnAddress類型,
局部變量表的內存空間在編譯期完成分配,當進入一個方法,這方法需要在幀分配多少內存是固定的,在方法運行期是不會改變局部變量表的大小(存儲的只是對象的引用)
1 public class Demo { 2 3 public void tes() { 4 System.out.println("方法執行...."); 5 tes(); 6 } 7 8 public static void main(String[] args) { 9 new Demo().tes(); 10 11 } 12 13 }
方法執行....
方法執行....
........
Exception in thread "main" java.lang.StackOverflowError
若不限定棧的內存,將超過虛擬機的內存,或物理內存,將拋出 OutofMemory
本地方法棧
虛擬機棧為虛擬機執行java方法服務,本地方法棧為虛擬機執行native方法服務
?
java堆
存儲對象實例
垃圾收集器管理的主要區域
新生代,老年代
?
方法區
存儲虛擬機加載的類信息(類的版本,字段,方法,接口),常量,靜態變量,即使編譯器編譯后的代碼等數據。
方法區和永久代
垃圾回收在方法區的行為(針對常量池的回收以及對象類型的卸載等)
異常的定義
OurOfMemoryError
?
運行時常量池,屬于方法區的
1 public class Test { 2 3 public static void main(String[] args) { 4 String s1 = "abc";//字節碼常量 5 String s2 = "abc";//字節碼常量 6 System.out.println(s1 == s2); 7 8 String s3 = new String("abc"); 9 10 System.out.println(s1 == s3); 11 12 System.out.println(s1 == s3.intern());//運行時常量 13 14 } 15 16 /** 17 * true 18 false 19 true 20 */ 21 }
?
任何字符串的創建都會放在常量池中,常量池在方法區中,運行時常量池維護了StringTable字符串表,數據類型可以是HashSet ,存放所實例的字符串對象,由于hashSet的無序和不可重復, abc 只創建了一個實例,即 s1 == s2
如果用new 創建一個對象一定是在堆內存開辟空間,不再考慮常量池的問題
intern()作用在jdk1.7之后是查看常量池中是否存在和調用方法的字符串內容一樣的字符串,如果有的話,就返回該常量池中的字符串,若沒有的話,就在常量池中寫入一個堆中該字符串對象的一個引用,指向堆中的該對象,并返回該引用。即是調用這個方法之后把字符串對象加入常量池中。
直接內存
能夠分配堆外內存,不受到java虛擬機內存的制約,會受到當前操作系統物理內存的制約
?
對象的結構:
Header 對象頭
自身運行時數據(Mark Word)
哈希值 GC分代年齡 鎖狀態標志 線程持有的索 偏向線程ID 偏向時間戳?
類型指針
對象指向它類的元數據的指針
InstanceData(相同的字段分配在一起)
Long dobles? ? shorts/chars??
Padding,對齊填充不是必須的,占位符,對象的大小必須是8個字節的整數倍。
?
?
對象的訪問定位
使用句柄:指向堆中的句柄池,保存了實例對象的地址,引用地址不需要修改。
直接指針,從引用類型直接指向真正的內存區域,速度快,性能高
兩者都要保存? 到對象實例數據的指針和到對象類型數據的指針
?
?
?
?