堆和棧都是Java中常用的存儲結構,都是內存中存放數據的地方。
堆:(對象)
引用類型的變量,其內存分配在堆上或者常量池(字符串常量、基本數據類型常量),需要通過new等方式來創建。
堆內存主要作用是存放運行時創建(new)的對象。
(主要用於存放對象,存取速度慢,可以運行時動態分配內存,生存期不需要提前確定)
棧:(基本數據類型變量、對象的引用變量)
基本數據類型的變量(int、short、long、byte、float、double、boolean、char等)以及對象的引用變量,其內存分配在棧上,變量出了作用域就會自動釋放。
棧內存的主要作用是存放基本數據類型和引用變量。棧的內存管理是通過棧的"後進先出"模式來實現的。
(主要用來執行程序,存取速度快,大小和生存期必須確定,缺乏靈活性)
為什麼有棧內存和堆內存之分?
當一個方法執行時,每個方法都會建立自己的內存棧,在這個方法定義的變量將會放到這塊棧內存裡,隨著方法的結束,這個方法的內存棧也將自動銷燬。(不需要GC回收)
因此,所有在方法中定義的局部變量放在棧內存中;
當我們在程序中創建一個對象時,這個對象會被保存到運行時數據區中,以便反覆利用(複用,因為創建對象的成本通常較大),這個運行時數據區就是堆內存。堆內存中的對象不會隨著方法的結束而銷燬,即使方法結束後,這個對象還可能被另外一個引用變量所引用(在方法的參數傳遞時很常見),則這個對象依然不會被銷燬。只有當一個對象沒有任何引用變量去引用它時,系統的垃圾回收器(GC)才會在合適的時候回收它。
為什麼上面說創建對象的開銷(成本)比較大?
來看看如何創建對象、創建對象的過程:
創建對象的根本途徑是構造器,通過new關鍵字來調用某個類的構造器即可創建這個類的實例。但對象不是完全由構造器來負責創建的,實際上,當程序員調用構造器時,系統會先為該對象分配內存空間,併為這個對象執行默認初始化,這個對象已經產生了---這些是在構造器執行之前就完成的,也就是說,當系統開始執行構造器的執行體之前,系統已經創建了一個對象,只是這對象還不能被外部程序訪問,只能在構造器中通過this來引用。當構造器的執行體執行結束後,這個對象作為構造器的返回值被返回,通常還會賦給另外一個引用類型的變量,從而讓外部程序可以訪問。(當然可以通過設置構造器的訪問權限private,阻止其他類創建該類的實例)
閱讀更多 龐小輝 的文章