溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java中的堆和棧是什么

發(fā)布時間:2023-04-27 10:19:50 來源:億速云 閱讀:129 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“Java中的堆和棧是什么”的相關(guān)知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Java中的堆和棧是什么”文章能幫助大家解決問題。

Java程序是怎么運行的

Java程序運行在Java Virtual Machine (JVM)中,JVM提供了Java應(yīng)用程序在運行時所需要的任何資源的管理器。這就意味著開發(fā)者寫的應(yīng)用程序或者創(chuàng)建的應(yīng)用程序沒有能力去直接獲取系統(tǒng)資源(不管是硬件還是軟件),除非JVM能提供給這些資源。所以在Java中,程序運行順序如下圖:

Java中的堆和棧是什么

JVM層使得Java平臺能夠獨立運行,其他編程語言,例如C/C++沒有使用類似JVM層的東西,因此它們不是跨平臺的語言,即使它們是可移植的語言。它們就像下圖一樣:

Java中的堆和棧是什么

這兩種形式有優(yōu)點也有缺點,Java已經(jīng)有了自己的生態(tài)系統(tǒng)。與此同時,像C/C++這樣的編程語言能夠直接訪問系統(tǒng)資源,從而更有利于優(yōu)化核心單元的使用,從而產(chǎn)生超級快速和高效的程序。但兩者在軟件開發(fā)領(lǐng)域都有各自的用途。

所有編程語言在編譯和執(zhí)行過程中都有許多相似之處。其中最重要的一點就是內(nèi)存管理,無論使用哪種語言,內(nèi)存管理對程序的整體效率都有重要影響,因為管理好內(nèi)存資源,從而才能管理好應(yīng)用程序性能。

Java中的運行內(nèi)存

應(yīng)用程序之間的一個常見現(xiàn)象是,每個應(yīng)用程序都需要一些內(nèi)存才能以最佳方式工作,該內(nèi)存由底層平臺提供。在Java中,JVM提供了這些內(nèi)存資源(當然需要操作系統(tǒng)授權(quán))。Java中,JVM內(nèi)存主要分為5個部分分別為:方法區(qū)、堆、棧、PC寄存器和本地方法區(qū)。

本文主要關(guān)注堆和棧。內(nèi)存不像一張白紙,程序員只需要草草記下就可以存儲數(shù)據(jù),在使用內(nèi)存之前,需要對其進行結(jié)構(gòu)化。棧和堆是使用內(nèi)存時遵循的數(shù)據(jù)結(jié)構(gòu),在程序執(zhí)行期間,存儲的數(shù)據(jù)用于各種目的,這取決于程序的目的是什么。

JVM決定程序執(zhí)行期間使用的運行時數(shù)據(jù)區(qū)域。有些數(shù)據(jù)區(qū)域是依賴于JVM的,這意味著它們是在JVM啟動時創(chuàng)建的,并在JVM的整個生命周期中持續(xù)存在。但是,每個線程都創(chuàng)建和銷毀其他數(shù)據(jù)區(qū)域。JVM可以同時執(zhí)行多個執(zhí)行線程,這意味著每個線程都有自己的pc(Program Counter,程序計數(shù)器)來維護正在執(zhí)行的當前指令的位置,還有一個棧幀來保存靜態(tài)內(nèi)存分配。

棧是內(nèi)存中的一種結(jié)構(gòu),開發(fā)人員在其中存儲元素,其方式允許只從棧頂檢索數(shù)據(jù)——通常稱為先入后出(FILO或LIFO)。因為每個線程都維護一個私有的JVM棧,它被用來存儲與它們的靜態(tài)內(nèi)存分配相關(guān)的變量。特定于我們在代碼中聲明和使用的方法的原語變量實際上存儲在棧區(qū)域中。另外,對實際存儲在堆內(nèi)存中的對象的引用也存儲在堆棧區(qū)域中。因此,任何本地分配的內(nèi)存都存儲在堆棧中。

堆棧內(nèi)存的默認大小可以使用JVM參數(shù)-Xss來更改。有時,如果分配了太多變量或方法遞歸調(diào)用自身,則堆??赡芤绯觥K蠮ava程序員都知道的一個常見錯誤是Java.lang.stackoverflowerror,當棧內(nèi)存不足時提示該錯誤。Java中的每個方法調(diào)用都會在棧中分配一塊內(nèi)存,因此,設(shè)計糟糕的遞歸方法調(diào)用很容易占用所有棧內(nèi)存,導(dǎo)致棧內(nèi)存溢出錯誤。

堆是JVM一啟動就創(chuàng)建的內(nèi)存區(qū)域,它會一直存在,直到JVM被銷毀。與棧不同的是,棧是單個線程的屬性(因為每個線程都有自己的棧),堆實際上是由JVM本身管理的全局內(nèi)存,此內(nèi)存在運行時用于為對象分配內(nèi)存。因此,對象的實例化可以是用戶定義的類、JDK或其他庫類。簡而言之,使用new關(guān)鍵字創(chuàng)建的任何對象都存儲在堆內(nèi)存中。堆內(nèi)存中的對象可被JVM運行的所有線程訪問。訪問管理非常復(fù)雜,使用了非常復(fù)雜的算法,這就是JVM垃圾收集器發(fā)揮作用的地方。

堆的默認大小可以使用JVM參數(shù)-Xms-Xmx來更改。隨著對象的創(chuàng)建和銷毀,堆的大小也會增加或減少,如果達到最大內(nèi)存限制后并嘗試進一步分配內(nèi)存,則拋出java.lang.OutOfMemoryError。

堆中的字符串池(StringPool)

Java.lang.String類是Java中使用最多的類,因此,應(yīng)該特別注意它的效率問題。與基本數(shù)據(jù)類型相比,字符串的操作效率總是很慢,所以,必須采用某種方式使得字符串對象操作的效率和便利性方面類似或者接近于基本數(shù)據(jù)類型,為了達到這個目的就在堆中分配了一塊特殊內(nèi)存區(qū)域(StringPool),創(chuàng)建的任何字符串對象都由JVM存儲在StringPool中。與堆中創(chuàng)建的其他對象相比,這提高了性能。

從代碼示例說明堆和棧

為了更好地說明在Java中堆和棧內(nèi)存的使用,讓我們寫一個簡單的程序,并決定哪個分配分配到哪個內(nèi)存——堆或棧:

public class HeapAndStackTest {
    public static void main(String[] args) {
        int x=10;
        int y=20;
        String greet = "Hello";
        Date d = new Date();
        diff(x, y);
    }

    public static int diff(int x1, int x2) {
        return x2-x1;
    }
}

這段代碼運行方式如下:

  • 程序啟動,JVM將Java運行時環(huán)境(JRE)類加載到堆中。

  • 在遇到main() 方法時,會創(chuàng)建一個棧幀。

  • 局部變量xy存儲在棧中。

  • 字符串greet分配在堆的StringPool區(qū)域中。

  • Date對象分配在堆區(qū),而它的引用d存儲在棧中。

Java中的堆和棧是什么

關(guān)于“Java中的堆和棧是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI