java堆內存和棧內存的區別

一段時間之前,我寫了兩篇文章文章分別是Java的垃圾回收和Java的值傳遞,從那之後我收到了很多要求解釋Java堆內存和棧內存的郵件,並且要求解釋他們的異同點。

在Java中你會看到很多堆和棧內存的引用,JavaEE書和文章很難在程序的角度完全解釋什麼是堆什麼是棧。


總結:
1 棧:爲編譯器自動分配和釋放,如函數參數、局部變量、臨時變量等等
2 堆:爲成員分配和釋放,由程序員自己申請、自己釋放。否則發生內存泄露。典型爲使用new申請的堆內容。
除了這兩部分,還有一部分是:
3 靜態存儲區:內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。它主要存放靜態數據、全局數據和常量。



Java堆內存

堆內存在Java運行時被使用來爲對象和JRE類分配內存。不論什麼時候我們創建了對象,它將一直會在堆內存上創建。垃圾回收運行在堆內存上來釋放沒有任何引用的對象所佔的內存,任何在堆上被創建的對象都有一個全局的訪問,並且可以在應用的任何位置被引用。

Java棧內存

Java的棧內存被用來線程的執行,他們包含生命週期很短的具體值的方法和在堆中使用這個方法對象的引用。棧內存是LIFO(後進先出)序列。當方法被調用的時候,堆內存中一個新的塊被創建,保存了本地原始值和在方法中對其他對象的引用。這個方法結束之後,這個塊對其他方法就變成可用的了。棧內存與堆內存相比是非常小的。
我們用下邊的例子理解堆內存和棧內存
  1. package com.journaldev.test;  
  2.    
  3. public class Memory {  
  4.    
  5.     public static void main(String[] args) { // Line 1  
  6.         int i=1// Line 2  
  7.         Object obj = new Object(); // Line 3  
  8.         Memory mem = new Memory(); // Line 4  
  9.         mem.foo(obj); // Line 5  
  10.     } // Line 9  
  11.    
  12.     private void foo(Object param) { // Line 6  
  13.         String str = param.toString(); //// Line 7  
  14.         System.out.println(str);  
  15.     } // Line 8  
  16.    
  17. }  

下邊的圖片展示了上邊程序堆和棧內存的引用,並且是怎麼用來存儲原始值、對象和變量的引用。


我們來看看程序執行的過程:
1、只要我們一運行這個程序,它會加載所有的運行類到堆內存中去,當在第一行找到main()方法的時候,Java創建可以被main()方法線程使用的棧內存。
2、當在第一行,我們創建了本地原始變量,它在main()的棧中創建和保存。
3、因爲我們在第三行創建了對象,它在堆內存中被創建,在棧內存中保存了它的引用,同樣的過程也發生在第四行我們創建Memory對象的時候。
4、當在第五行我們調用foo()方法的時候,在堆的頂部創建了一個塊來被foo()方法使用,因爲Java是值傳遞的,在第六行一個新的對象的引用在foo()方法中的棧中被創建
5、在第七行一個String被創建,它在堆空間中的String池中運行,並且它的引用也在foo()方法的棧空間中被創建
6、foo()方法在第八行結束,此時在堆中爲foo()方法分配的內存塊可以被釋放
7、在第九行,main()方法結束,棧爲main()方法創建的內存空間可以被銷燬。同樣程序也在行結束,Java釋放了所有的內存,結束了程序的運行

堆內存和棧內存的區別

基於上邊的解釋我們可以很簡單的總結出堆和棧的區別:
1、應用程序所有的部分都使用堆內存,然後棧內存通過一個線程運行來使用。
2、不論對象什麼時候創建,他都會存儲在堆內存中,棧內存包含它的引用。棧內存只包含原始值變量好和堆中對象變量的引用。
3、存儲在堆中的對象是全局可以被訪問的,然而棧內存不能被其他線程所訪問。
4、棧中的內存管理使用LIFO的方式完成,而堆內存的管理要更復雜了,因爲它是全局被訪問的。堆內存被分爲,年輕一代,老一代等等,更多的細節請看,這篇文章
5、棧內存是生命週期很短的,然而堆內存的生命週期從程序的運行開始到運行結束。
6、我們可以使用-Xms和-Xmx JVM選項定義開始的大小和堆內存的最大值,我們可以使用-Xss定義棧的大小
7、當棧內存滿的時候,Java拋出java.lang.StackOverFlowError異常而堆內存滿的時候拋出java.lang.OutOfMemoryError: Java Heap Space錯誤
8、和堆內存比,棧內存要小的多,因爲明確使用了內存分配規則(LIFO),和堆內存相比棧內存非常快。

原文地址:http://www.journaldev.com/4098/java-heap-memory-vs-stack-memory-difference

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