1. 程式人生 > >java程式設計中的堆與棧,你瞭解多少?

java程式設計中的堆與棧,你瞭解多少?

在JVM中記憶體有這5類

堆(Heap)存放關鍵字new建立的物件和陣列;java堆是jvm記憶體管理中最大的一塊,執行緒共享;當使用new建立物件時,不必指定分配空間的大小,jvm會動態自動分配一塊區域;在程式執行過程中,沒有指向此物件的引用時,此物件就被標記為可被回收狀態,將由GC(垃圾回收器)在一個不確定的時間自動回收,釋放所佔的記憶體空間。在jvm啟動的時候建立。此區域唯一目的就是存放物件例項,幾乎所有的物件例項都在這裡分配記憶體。但是隨著JIT編譯器(即時編譯器)的發展與逃逸分析技術的逐漸成熟,棧上分配、標量替換優化技術將會導致一些微妙變化(物件可能會分配到棧上),所以這種所有物件都分配在堆上也不是那麼絕對的。虛擬機器棧(VM Stack)存放8種基本型別的資料和物件引用(不是物件)。每個執行緒有自己的單獨的棧。先進後出,後進先出。因為主要存放基本型別資料變數,所以分配空間比堆快。當超出變數的作用域,將由編譯器立即釋放空間。

小編是一個有著5年工作經驗的java程式設計師,對於java,自己有做資料的整合,一個完整學習java的路線,學習資料和工具,相信這裡有很多學習java的小夥伴,我創立了一個2000人學習扣群,479121291。每晚都有java的直播課程。無論是初級還是進階的小夥伴小編我都歡迎!

本地方法棧(Native Method Stack)

程式呼叫本地方法的記憶體區域。程式計數器 (Program Counter Register)

一塊較小的記憶體空間,可看作是當前執行緒所執行的位元組碼的 行號指示器。

通過改變計數器的值來選取下一條需要執行的位元組碼指令。(分支、迴圈、跳轉、異常處理、執行緒恢復等)基礎功能都依賴與其完成。

特點:執行緒私有:因為 Java 虛擬機器的多執行緒是通過 執行緒輪流切換 並 分配處理器執行時間 來實現的,在某一時刻,只會執行一條執行緒。因此,為了執行緒切換後能恢復到正確的執行位置,每條執行緒都需要有一個獨立的程式計數器。無記憶體溢位:如果執行緒正在執行的是一個 Java 方法,這個計數器記錄的是正在 執行的虛擬機器位元組碼指令的地址;如果正在執行的是 Native 方法,這個計數器值則為空(Undefined)。此記憶體區域是唯一一個在 Java 虛擬機器程式規範中沒有規定任何 OutOfMemoryError 情況的區域。

方法區(Method Area)跟堆一樣,被所有的執行緒共享。在裝載類檔案時,用於儲存型別資訊(類的描述資訊):是一個記憶體邏輯區域,是JVM在裝載類檔案時,用於儲存型別資訊(類的描述資訊):執行時常量池:在方法區中,每個型別都對應一個常量池,存放該型別所用到的所有常量,常量池中儲存了諸如文字字串、final變數值、類名和方法名常量。它們以陣列形式通過索引被訪問,是外部呼叫與類聯絡及型別物件化的橋樑。(存的可能是個普通的字串,然後經過常量池解析,則變成指向某個類的引用)

欄位資訊:欄位資訊存放類中宣告的每一個欄位的資訊,包括欄位的名、型別、修飾符。

欄位名稱指的是類或介面的例項變數或類變數,欄位的描述符是一個指示欄位的型別的字串,如private A a=null;則a為欄位名,A為描述符,private為修飾符。

方法資訊:類中宣告的每一個方法的資訊,包括方法名、返回值型別、引數型別、修飾符、異常、方法的位元組碼。

(在編譯的時候,就已經將方法的區域性變數、運算元棧大小等確定並存放在位元組碼中,在裝載的時候,隨著類一起裝入方法區。)靜態成員變數:類中的靜態成員變數和靜態程式碼塊。到類classloader的引用:到該類的類裝載器的引用。到類class的引用:虛擬機器為每一個被裝載的型別建立一個class例項,用來代表這個被裝載的類。每個類的全限定名每個類的直接超類的全限定名(可約束型別轉換)該類是類還是介面該型別的訪問修飾符直接超介面的全限定名的有序列表類的基本資訊:已裝載類的詳細資訊:棧是執行時的單位,而堆是儲存的單位。

總結堆與棧的關係棧是執行時的單位,而堆是儲存的單位。堆和棧中,棧是程式執行最根本的東西。程式執行可以沒有堆,但是不能沒有棧。而堆是為棧進行資料儲存服務,說白了堆就是一塊共享的記憶體。不過,正是因為堆和棧的分離的思想,才使得Java的垃圾回收成為可能。Java中,棧的大小通過-Xss來設定,當棧中儲存資料比較多時,需要適當調大這個值,否則會出現java.lang.StackOverflowError異常。常見的出現這個異常的是無法返回的遞迴,因為此時棧中儲存的資訊都是方法返回的記錄點。