1. 程式人生 > >Java開發中堆記憶體與棧記憶體都有哪些區別?

Java開發中堆記憶體與棧記憶體都有哪些區別?

在這裡插入圖片描述

Java把記憶體劃分成兩種:一種是棧記憶體,一種是堆記憶體。
一、棧記憶體
存放基本型別的變數,物件的引用和方法呼叫,遵循先入後出的原則。
棧記憶體在函式中定義的“一些基本型別的變數和物件的引用變數”都在函式的棧記憶體中分配。
當在一段程式碼塊定義一個變數時,Java就在棧中為這個變數分配記憶體空間,當超過變數的作用域後,Java會自動釋放掉為該變數所分配的記憶體空間,該記憶體空間可以立即被另作他用。
Java中的程式碼是在函式體中執行的,每個函式主體都會被放在棧記憶體中,比如main函式。
假如main函式裡呼叫了其他的函式,比如add(),那麼在棧裡面的的儲存就是最底層是main,mian上面是add。
棧的執行時後入先出的,所以會執行時會先銷燬add,再銷燬main。
棧的優勢是,棧記憶體與堆記憶體相比是非常小的,存取速度比堆要快,僅次於暫存器,棧資料可以共享。但缺點是,存在棧中的資料大小與生存期必須是確定的,缺乏靈活性。
棧中主要存放一些基本型別的變數(int, short, long, byte, float, double, boolean, char)和物件控制代碼。
棧有一個很重要的特殊性,就是存在棧中的資料可以共享。
二、堆記憶體
存放所有new出來的物件和陣列
特此強調,堆記憶體和資料結構中的堆完全是兩碼事,分配方式倒是類似於連結串列
堆記憶體是區別於棧區、全域性資料區和程式碼區的另一個記憶體區域。
堆允許程式在執行時動態地申請某個大小的記憶體空間,堆記憶體實際上指的就是(滿足堆記憶體性質的)優先佇列的一種資料結構,第1個元素有最高的優先權。
在堆記憶體分配時首先應該知道作業系統有一個記錄空閒記憶體地址的連結串列,當系統收到程式的申請時,會遍歷該連結串列,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點連結串列中刪除,並將該結點的空間分配給程式,另外,對於大多數系統,會在這塊記憶體空間中的首地址處記錄本次分配的大小,這樣,程式碼中的delete語句才能正確的釋放本記憶體空間。
另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒連結串列中。
堆記憶體是向高地址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用連結串列來儲存的空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由低地址向高地址。
堆記憶體的大小受限於計算機系統中有效的虛擬記憶體。由此可見,堆記憶體獲得的空間比較靈活,也比較大。
堆記憶體是由new分配的記憶體,一般速度比較慢,而且容易產生記憶體碎片,不過用起來最方便。
棧與堆都是Java用來在Ram中存放資料的地方。與C ++不同,Java自動管理棧和堆,程式設計師不能直接設定棧或堆
Java的堆是一個執行時資料區,類的(物件從中分配空間。
這些物件通過新的,newarray,anewarray和multianewarray等指令建立,它們不需要程式程式碼來顯式的釋放。
堆是由垃圾回收來負責的,堆的優勢是可以動態地分配記憶體大小,生存期也不必事先告訴編譯器,因為它是在執行時動態分配記憶體的,Java的的垃圾收集器會自動收走這些不再使用的資料。
但缺點是,由於要在執行時動態分配記憶體,存取速度較慢。
三、其他資料儲存
1、常量池:存放基本型別常量和字串常量(public static final)
2、靜態域:存放靜態成員(static定義的)
3、非RAM儲存:硬碟等永久儲存空間

堆記憶體和棧記憶體的區別:
1、應用程式所有的部分都使用堆記憶體,然後棧記憶體通過一個執行緒執行來使用。
2、不論物件什麼時候建立,他都會儲存在堆記憶體中,棧記憶體包含它的引用。棧記憶體只包含原始值變數好和堆中物件變數的引用。
3、儲存在堆中的物件是全域性可以被訪問的,然而棧記憶體不能被其他執行緒所訪問。
4、棧中的記憶體管理使用LIFO的方式完成,而堆記憶體的管理要更復雜了,因為它是全域性被訪問的。
5、棧記憶體是生命週期很短的,然而堆記憶體的生命週期從程式的執行開始到執行結束。
6、我們可以使用-Xms和-Xmx JVM選項定義開始的大小和堆記憶體的最大值,我們可以使用-Xss定義棧的大小
7、當棧記憶體滿的時候,Java丟擲java.lang.StackOverFlowError異常而堆記憶體滿的時候丟擲java.lang.OutOfMemoryError: Java Heap Space錯誤
8、和堆記憶體比,棧記憶體要小的多,因為明確使用了記憶體分配規則(LIFO),和堆記憶體相比棧記憶體非常快。總結:
1 棧:為編譯器自動分配和釋放,如函式引數、區域性變數、臨時變數等等
2 堆:為成員分配和釋放,由程式設計師自己申請、自己釋放。否則發生記憶體洩露。典型為使用new申請的堆內容。
除了這兩部分,還有一部分是:
3 靜態儲存區:記憶體在程式編譯的時候就已經分配好,這塊記憶體在程式的整個執行期間都存在。它主要存放靜態資料、全域性資料和常量。
文章來自:

https://www.itjmd.com/news/show-5317.html