在我們開發運維過程中會碰到好多關於堆內存溢出,還有持久代內存溢出等各種故障;有時候java堆內存管理是影響應用性能的主要因素之一;瞭解jvm內存結構會方便我們在服務器出現性能問題時候快速瞭解和解決問題。
1. java內存結構:
1.1 上圖可獲取到數據Java內存結構主要有三塊:堆內存,方法區和棧。堆內存是jvm中最大的一塊由年輕代和老年代組成,而年輕代內存又被劃分爲:Eden空間,From Survivor空間,To Survivor空間,默認下年輕代按照8:1:1比例分配;方法區存儲類信息,常量,靜態變量等數據,是線程共享的區域,爲與java堆區分,方法區還有一個別名Non-Heap(非堆);棧又分爲java虛擬機棧和本地方法棧主要用於方法的執行。
1.2 在瞭解了java內存結構後我們更想知道內存分配和調整來提升我們應用在使用中性能;
參數詳解:
-Xms 堆的最小空間大小
-Xmx 堆的最大空間大小
-XX:NewSiza 新生代最小空間大小
-XX:MaxNewSize 新生代最大空間大小
-XX:PermSize 永久代最小空間大小
-XX:MaxPermSiza 永久代最大空間大小
-Xss 每個線程的堆棧大小
沒有直接設置老年代的參數,但是可以通過設置堆內存大小和新生代空間來間接控制(老年代空間=堆空間-年輕代空間)
方法區和堆是所有線程共享的內存區域,java棧,本地方法棧和程序員計數器是運行在線程私有的內存區域:
2. 每個區域作用:
2.1 java堆(Heap)
堆內存劃分:
a. 包含伊甸(Eden)和倖存者區(survivor space)的新生代(young generation)
b. 老年代(Old generation)
對象和類的數據存儲在3個不同的內存區域:堆(heap space),方法區(method area),本地區(native area)
堆內存存放對象以及數組的數據,方法區存放類的信息(類名,方法,字段),靜態變量,編譯器編譯後的代碼,本地區包含線程棧,本地方法棧等存放線程,方法區有時被稱爲持久代(PermGen)
對於大多數應用來說,java堆(java Heap)是java虛擬機所管理的內存中最大的一塊,被所有的線程共享的一塊區域,在虛擬機啓動時創建,目的就是存放對象實例,幾乎所有的對象實例都在堆中分配內存;
java堆是垃圾回收的主要區域,因此被稱作GC堆;根據java虛擬機規範;java堆可以處於物理上不連續的內存空間中,只要是邏輯上連續的就可,就像磁盤空間一樣,在實現時,既可以實現成固定大小,也可以是可擴展的,當前是通過參數-Xmx和-Xms控制;
2.2 方法區(Method Area)
方法區也是各個線程共享的內存區域,用於存儲已經被虛擬機加載的類信息,常量,靜態變量,即時編譯器編譯後的代碼等數據,雖然java虛擬機規範吧方法區描述爲堆的一個邏輯部分,但是他卻有一個別名叫Non-Heap(非堆);對於在HotSpot虛擬機開發和部署程序來說,吧方法區稱爲永久代,本質是不等價的,是因爲這個虛擬機設計團隊選擇吧GC分代收集擴展至方法區,或者說使用永久代來實現方法區;
java虛擬機規範對於這個區域的限制非常寬鬆,除了和java堆一樣不需要連續的內存和可以選擇固定大小或者可擴展外,還可以選擇不實現垃圾收集,相對而言,垃圾收集行爲在這個區域是比較少見的,但並非數據進入了方法區就如永久代名字一樣;永久存在了;這個區域的內存回收主要是針對常量池的回收和對類型的卸載,;根據java虛擬機規範的規定,當方法區無法滿足內存分配時候;將拋出OutOfMemoryError異常。
2.3 java棧(stacks)
java虛擬機棧線程私有的,他的生命週期與線程相同,虛擬機棧描述的是java方法執行的內存模型:每個方法被執行的時候都會同事創建一個棧幀用於存儲局部變量表,操作站,動態鏈接,方法出口等信息,每一個方法被調用直至執行完成的過程,對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。局部變量表存放了編譯器剋制的各種基本數據類型(byte, char, short, int, float, long, double, boolean),對象引用和returnAddress類型;在java虛擬機規範中異常:線程請求的棧深度大於虛擬機所允許的深度,將拋出StackOverfloeError異常;虛擬機棧可以動態擴展,當擴展無法申請到足夠的內存時會拋出OutOfMemoryError異常。
3. 瞭解不同的OutOfMemoryError
Exception in thread "main":java.lang.OutOfMemoryError: java heap space 對象不能被分配到堆內存中
Exception in thread "main":java.lang.OutOfMemoryError: Requested array size exceeds VM limit 創建的數組大於堆內存空間
Exception in thread "main":java.lang.OutOfMemoryError: request<size> bytes for <reason>.Out of swap space? 分配本地分配失敗,JNI,本地庫或者java虛擬機都會從本地堆中分配內存空間
Exception in thread "main":java.lang.OutOfMemoryError:<reason> <stack trace>(Native method) 本地方法內存分配失敗,只不過是JNI或者本地方法或者java虛擬機發現。