Java堆與棧的基本理解

Java堆與棧的基本理解

最新的一次面試,我們聊到了JVM,今天在這兒想要系統的回顧一下,記錄在此,時常看看,增加自己的印象。

Java虛擬機運行時數據區

首先,線程隔離的數據區域內包含:程序計數器、虛擬機棧、本地方法棧。
其次,所有線程共享的數據區域包含:堆、方法區、運行時常量。

程序計數器

程序計數器是一個記錄着當前線程所執行的字節碼的行號指示器。
字節碼解釋器工作是就是通過改變這個計數器的值來選取下一條需要執行指令的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能都需要依賴計數器完成。此內存區域是唯一一個沒有規定任何OutOfMemoryError情況的區域。線程私有。
如果線程正在執行一個 Java 方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址,如果線程執行的是一個Native方法,計數器值則爲空。

虛擬機棧

Java虛擬機棧也是線程私有的,它的生命週期與線程相同(隨線程而生,隨線程而滅),Java虛擬機棧描述的是Java方法執行的內存模型:每個方法執行的同時會創建一個棧幀,用於存儲局部變量表操作數棧、動態鏈接、方法出口等信息。每一個方法從調用直至執行結束,就對應着一個棧幀從虛擬機棧中入棧到出棧的過程。
(局部變量表(Local Variable Table)是一組變量值存儲空間,用於存放方法參數和方法內部定義的局部變量, 並且在Java編譯爲Class文件時,就已經確定了該方法所需要分配的局部變量表的最大容量。局部變量表存放了編譯期可知的各種基本數據類型(boolean、byte、char、short、int、float、long、double對象引用(reference類型) 和 returnAddress類型,也可以說基本數據和對象引用存儲在棧的局部變量表中
如果線程請求的棧深度大於虛擬機所允許的深度,將拋出StackOverflowError異常,如果虛擬機棧可以動態擴展,如果擴展時無法申請到足夠的內存,就會拋出OutOfMemoryError異常(當前大部分JVM都可以動態擴展,只不過JVM規範也允許固定長度的虛擬機棧)。

本地方法棧

和Java虛擬機棧十分相似,差別不過是Java虛擬機棧是爲了Java虛擬機執行字節碼所服務,而本地方法棧則是爲了執行native方法所服務的,所以本地方法也是一個私有的內存區域,也是後進先出棧,作用是支撐native方法的調用,執行和退出與java虛擬機棧一樣也會出現StackOverflowError 和 OutOfMemoryError 異常。

堆是 JVM 管理的最大的一塊內存空間,主要用於存放Java類的實例對象,其被劃分爲三個不同的區域:新生代 ( Young )和老年代 ( Old )和永久代(Pem),從Java8中元空間替代了永久代。
Java堆可以處於物理上不連續的內存空間中,並且可以動態擴展其內存,擴展失敗將會拋出OutOfMemoryError異常。
堆內存中存儲的全部是對象,所有的實體都有內存地址值。當這些實體不再被指向時,JVM啓動垃圾回收機制。

方法區

用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。與堆一樣是線程共享的內存區域,也不需要連續的內存,可動態擴展內存,擴展失敗一樣會拋出OutOfMemoryError異常。

常量池

這裏說到的是運行時常量池。屬於方法區一部分,用於存放編譯期生成的各種字面量和符號引用。編譯器和運行期都可以將常量放入池中。內存有限,無法申請時拋出 OutOfMemoryError。
網上常用的案例:

String s1 = "Hello";	 
String s2 = new String("Hello");
String s3 = s2.intern();

其中s1和s3爲什麼相等呢?原因在於intern方法,這個方法首先在常量池中查找是否存在一份equal相等的字符串如果有的話就返回該字符串的引用,沒有的話就將它加入到字符串常量池中,所以存在於class中的常量池並非固定不變的,可以用intern方法加入新的。

總結

我們面試中常會問到堆棧的問題。
函數中定義的基本類型變量,對象的引用變量都在函數的棧內存中分配。棧內存特點是數據一執行完畢,變量會立即釋放,節約內存空間。棧內存中的數據,沒有默認初始化值,需要手動設置。(String s = “abc”,其中s就是在棧中)
堆內存用來存放new創建的對象和數組。堆內存中所有的實體都有內存地址值。堆內存中的實體是用來封裝數據的,這些數據都有默認初始化值,當實體不再被指向時,JVM啓動垃圾回收機制,自動清除。(String s= new String ("abc),其中這個new的對象則是在堆中)
常見的面試問題->String s = new String(“abc”)產生幾個對象?->該問題涉及到常量池,如果之前常量池沒有“abc”這個對象,則會先在常量池中創建一個該字符串對象,然後在堆中創建一個拷貝對象,這樣的話則會產生2個對象;如果常量池中有該對象,則只創建一個對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章