標籤:
java記憶體分區
運行時資料區即是java記憶體,而且資料區要儲存的東西比較多,如果不對這塊記憶體地區進行劃分管理,會顯得比較雜亂無章。程式喜歡有規律的東西,最討厭雜亂無章的東西。
根據儲存資料的不同,java記憶體通常被劃分為5個地區:程式計數器(Program Count Register)、本地方法棧(Native Stack)、方法區(Methon Area)、棧(Stack)、堆(Heap)。
程式計數器(Program Count Register)
又叫程式寄存器。JVM支援多個線程同時運行,當每一個新線程被建立時,它都將得到它自己的PC寄存器(程式計數器)。如果線程正在執行的是一個Java方法(非native),那麼PC寄存器的值將總是指向下一條將被執行的指令,如果方法是 native的,程式計數器寄存器的值不會被定義。 JVM的程式計數器寄存器的寬度足夠保證可以持有一個返回地址或者native的指標。
棧(Stack):
又叫堆棧。JVM為每個新建立的線程都分配一個棧。也就是說,對於一個Java程式來說,它的運行就是通過對棧的操作來完成的。棧以幀為單位儲存線程的狀態。
JVM對棧只進行兩種操作:以幀為單位的壓棧和出棧操作。我們知道,某個線程正在執行的方法稱為此線程的當前方法。我們可能不知道,當前方法使用的幀稱為當前幀。當線程啟用一個Java方法,JVM就會線上程的 Java堆棧裡新壓入一個幀,這個幀自然成為了當前幀。在此方法執行期間,這個幀將用來儲存參數、局部變數、中間計算過程和其他資料。
從Java的這種分配機制來看,堆棧又可以這樣理解:棧(Stack)是作業系統在建立某個進程時或者線程(在支援多線程的作業系統中是線程)為這個線程建立的儲存地區,該地區具有先進後出的特性。
其相關設定參數:
-Xss --設定方法棧的最大值
本地方法棧(Native Stack):
儲存本地方方法的調用狀態。
方法區(Method Area):
當虛擬機器裝載一個class檔案時,它會從這個class檔案包含的位元據中解析類型資訊,然後把這些類型資訊(包括類資訊、常量、靜態變數等)放到方法區中,該記憶體地區被所有線程共用,如所示。本地方法區存在一塊特殊的記憶體地區,叫常量池(Constant Pool),這塊記憶體將與String類型的分析密切相關。
堆(Heap):
Java堆(Java Heap)是Java虛擬機器所管理的記憶體中最大的一塊。Java堆是被所有線程共用的一塊記憶體地區。在此地區的唯一目的就是存放對象執行個體,幾乎所有的對象執行個體都是在這裡分配記憶體,但是這個對象的引用卻是在棧(Stack)中分配。
如,執行String s = new String("s")時,需要從兩個地方分配記憶體:在堆中為String對象分配記憶體,在棧中為引用(這個堆對象的記憶體位址,即指標)分配記憶體,如所示。
JAVA虛擬機器有一條在堆中分配新對象的指令,卻沒有釋放記憶體的指令,正如你無法用Java代碼區明確釋放一個對象一樣。虛擬機器自己負責決定如何以及何時釋放不再被啟動並執行程式引用的對象所佔據的記憶體,通常,虛擬機器把這個任務交給垃圾收集器(Garbage Collection)。其相關設定參數:
-Xms -- 設定堆記憶體初始大小-Xmx -- 設定堆記憶體最大值-XX:MaxTenuringThreshold -- 設定對象在新生代中存活的次數-XX:PretenureSizeThreshold -- 設定超過指定大小的大對象直接分配在舊生代中
Java堆是垃圾收集器管理的主要區域,因此又稱為“GC 堆”(Garbage Collectioned Heap)。現在的垃圾收集器基本都是採用的分代收集演算法,所以Java堆還可以細分為:新生代(Young Generation)和老年代(Old Generation),如所示。分代收集演算法的思想:第一種說法,用較高的頻率對年輕的對象(young generation)進行掃描和回收,這種叫做minor collection,而對老對象(old generation)的檢查回收頻率要低很多,稱為major collection。這樣就不需要每次GC都將記憶體中所有對象都檢查一遍,以便讓出更多的系統資源供應用系統使用;另一種說法,在指派至遇到記憶體不足時,先對新生代進行GC(Young GC);當新生代GC之後仍無法滿足記憶體空間分配需求時, 才會對整個堆空間以及方法區進行GC(Full GC)。
在這裡可能會有讀者表示疑問:記得還有一個什麼永久代(Permanent Generation)的啊,難道它不屬於Java堆?親,你答對了!其實傳說中的永久代就是上面所說的方法區,存放的都是jvm初始化時載入器載入的一些類型資訊(包括類資訊、常量、靜態變數等),這些資訊的生存周期比較長,GC不會在主程式運行期對PermGen Space進行清理,所以如果你的應用中有很多CLASS的話,就很可能出現PermGen Space錯誤。其相關設定參數:
-XX:PermSize --設定Perm區的初始大小-XX:MaxPermSize --設定Perm區的最大值
新生代(Young Generation)又分為:Eden區和Survivor區,Survivor區有分為From Space和To Space。Eden區是對象最初分配到的地方;預設情況下,From Space和To Space的地區大小相等。JVM進行Minor GC時,將Eden中還存活的對象拷貝到Survivor區中,還會將Survivor區中還存活的對象拷貝到Tenured區中。在這種GC模式下,JVM為了提升GC效率, 將Survivor區分為From Space和To Space,這樣就可以將對象回收和對象晉陞分離開來。新生代的大小設定有2個相關參數:
老年代(Old Generation): 當 OLD 區空間不夠時, JVM 會在 OLD 區進行 major collection ;完全垃圾收集後,若Survivor及OLD區仍然無法存放從Eden複製過來的部分對象,導致JVM無法在Eden區為新對象建立記憶體地區,則出現"Out of memory錯誤" 。
Java基礎-JVM堆與棧