java五大記憶體區域
一:棧
Java棧的區域很小,只有1M,特點是存取速度很快,所以在stack中存放的都是快速執行的任務,基本資料型別的資料,和物件的引用(reference)。
棧指標若向下移,會建立新的記憶體;若向上移,則會釋放那些記憶體。這是一種特別快、特別有效的資料儲存方式,僅次於暫存器。
Java編譯器必須準確地知道堆疊內儲存的所有資料的“長度”以及“存在時間”。這是由於它必須生成相應的程式碼,以便向上和向下移動指標。這一限制無疑影響了程式的靈活性,所以儘管有些Java資料要儲存在棧裡——特別是物件控制代碼,但Java物件並不放到其中。
JVM只會直接對JavaStack(Java棧)執行兩種操作:
①以幀為單位的壓棧或出棧;
②通過-Xss來設定, 若不夠會丟擲StackOverflowError異常。
1.每個執行緒包含一個棧區,棧中只儲存基本資料型別的資料和自定義物件的引用(不是物件),物件都存放在堆區中
2.每個棧中的資料(原始型別和物件引用)都是私有的,其他棧不能訪問。
3.棧分為3個部分:基本資料型別的變數區、執行環境上下文、操作指令區(存放操作指令)。
棧是存放執行緒呼叫方法時儲存區域性變量表,操作,方法出口等與方法執行相關的資訊,Java棧所佔記憶體的大小由Xss來調節,方法呼叫層次太多會撐爆這個區域。
二:堆
類的物件放在heap(堆)中,所有的類物件都是通過new方法建立,建立後,在stack(棧)會建立類物件的引用(記憶體地址)。
“記憶體堆”或“堆”最吸引人的地方在於編譯器不必知道要從堆裡分配多少儲存空間,也不必知道儲存的資料要在堆裡停留多長的時間。因此,用堆儲存資料時會得到更大的靈活性。要求建立一個物件時,只需用new命令編輯相應的程式碼即可。執行這些程式碼時,會在堆裡自動進行資料的儲存。當然,為達到這種靈活性,必然會付出一定的代價:在堆裡分配儲存空間時會花掉更長的時間。
JVM將所有物件的例項(即用new建立的物件)(對應於物件的引用(引用就是記憶體地址))的記憶體都分配在堆上,堆所佔記憶體的大小由-Xmx指令和-Xms指令來調節
三:程式計數器(ProgramCounter)暫存器
PC暫存器( PC register ):每個執行緒啟動的時候,都會建立一個PC(Program Counter,程式計數器)暫存器。PC暫存器裡儲存有當前正在執行的JVM指令的地址。 每一個執行緒都有它自己的PC暫存器,也是該執行緒啟動時建立的。儲存下一條將要執行的指令地址的暫存器是 :PC暫存器。PC暫存器的內容總是指向下一條將被執行指令的地址,這裡的地址可以是一個本地指標,也可以是在方法區中相對應於該方法起始指令的偏移量。
四:本地方法棧:儲存native方法進入區域的地址。
五:方法區
method(方法區)又叫靜態區,存放所有的:
①:類(class)
②: 靜態變數(static變數)
③:靜態方法
④:常量
⑤:成員方法
1.又叫靜態區,跟堆一樣,被所有的執行緒共享。
2.方法區中存放的都是在整個程式中永遠唯一的元素。這也是方法區被所有的執行緒共享的原因。
靜態變數和常量的區別: 靜態變數本質是變數,是整個類所有物件共享的一個變數,其值一旦改變對這個類的所有物件都有影響;常量一旦賦值後不能修改其引用,其中基本資料型別的常量不能修改其值。
方法區的大小由-XX:PermSize和-XX:MaxPermSize來調節,類太多有可能撐爆永久代。靜態變數或常量也有可能撐爆方法區。
執行時常量池:
執行時常量池是方法區的一部分。CLass檔案中除了有類的版本、欄位、方法、介面等描述資訊外,還有一項資訊是常量池,用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類載入後進入方法區的執行時常量池中存放。
執行時常量池相對於CLass檔案常量池的另外一個重要特徵是具備動態性,Java語言並不要求常量一定只有編譯期才能產生,也就是並非預置入CLass檔案中常量池的內容才能進入方法區執行時常量池,執行期間也可能將新的常量放入池中,這種特性被開發人員利用比較多的就是String類的intern()方法。
常量池的好處
常量池是為了避免頻繁的建立和銷燬物件而影響系統性能,其實現了物件的共享。例如字串常量池,在編譯階段就把所有的字串文字放到一個常量池中。
(1)節省記憶體空間:常量池中所有相同的字串常量被合併,只佔用一個空間。
(2)節省執行時間:比較字串時,==比equals()快。對於兩個引用變數,只用==判斷引用是否相等,也就可以判斷實際值是否相等
什麼是常量
用final修飾的成員變量表示常量,值一旦給定就無法改變!
final修飾的變數有三種:靜態變數、例項變數和區域性變數,分別表示三種類型的常量。
Java中的常量池,實際上分為兩種形態:靜態常量池和執行時常量池
1:所謂靜態常量池,即*.class檔案中的常量池,class檔案中的常量池不僅僅包含字串(數字)字面量,還包含類、方法的資訊,佔用class檔案絕大部分空間。
2:而執行時常量池,則是jvm虛擬機器在完成類裝載操作後,將class檔案中的常量池載入到記憶體中,並儲存在方法區中,我們常說的常量池,就是指方法區中的執行時常量池。
常量池(constant_pool)指的是在編譯期被確定,並被儲存在已編譯的.class檔案中的一些資料。它包括了關於類、方法、介面等中的常量,也包括字串常量和符號引用。
常量池主要用於存放兩大類常量:
字面量(Literal)和符號引用量(SymbolicReferences)
字面量相當於Java語言層面常量的概念,如文字字串,宣告為final的常量值等
符號引用則屬於編譯原理方面的概念,
包括瞭如下三種類型的常量:
類和介面的全限定名;
欄位名稱和描述符;
方法名稱和描述符
-------------------------------------------------------------------------------------------------------------------
虛擬機器棧的內部結構:
虛擬機器棧在執行時使用一種叫作 棧幀的資料結構儲存上下文資料,棧幀由三部分組成:
區域性變數(Local Variables):被定義為一個從0開始的數字陣列,byte, short, char,boolean 在儲存前被換為int,0表示 false ,非 0 表示true,long和double 則佔據兩個字長,區域性變數區是通過陣列下標訪問的。
運算元棧(Operand Stack):也被組織為一個數字陣列,但不同於區域性變數區,它不是通過陣列下標訪問的而是通過棧的 Push 和Pop 操作,前一個操作Push 進的資料可以被下一個操作 Pop 出來使用。
幀資料區(Frame Data):作用主要有三點:
1:解析常量池裡面的資料
2:方法執行完後處理方法返回,恢復呼叫方現場;
3:方法執行過程中 丟擲異常時的異常處理,儲存在一個異常表,當出現異常時虛擬機器查詢相應的異常表看是否有對應的Catch 語句,如果沒有就丟擲異常終止這個方法呼叫。
————————————————
版權宣告:本文為CSDN博主「Java技術踐行者」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/eafun_888/article/details/92838103