1. 程式人生 > 其它 >java五大記憶體區域

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