JVM學習筆記(一)記憶體區域
一.jvm記憶體結構
線程私有
- 虛拟機棧
- 本地方法棧
- 程式計數器
線程共享
- 堆
- 方法區
- 直接記憶體區
二.程式計數器
作用:
- 位元組碼的行号訓示器: 位元組碼解釋器通過改變程式計數器來依次讀取指令,實作代碼的流程控制:順序執行,選擇,循環,異常處理
- 程式計數器用于記錄目前線程執行的位置,幫助應用進行線程間切換
唯一不會出現OutOfMemoryError記憶體區域,生命周期線程建立而建立,線程結束而死亡
三.java虛拟機棧
特點:
- 線程私有
- 生命周期線程建立而建立,線程結束而死亡
方法調用的資料通過棧傳遞,每一個方法調用都會進入對應的棧幀被壓入棧中,每一個方法調用結束後都會有一個棧幀彈出
每個棧幀:
- 局部變量表
- 操作數棧
- 動态連結
- 方法傳回位址
局部變量表
- 編譯期間可知的各種資料類型(boolean,byte,char,short,int,float,long,double),對象引用(rerence類型,引用指針或對象句柄)
操作數棧
- 方法調用的中轉站,存放方法執行過程中産生的中間計算結果或者臨時變量
動态連結-------- 一個方法需要調用其他方法的場景
- java源檔案被編譯成位元組碼檔案時,所有的變量和方法引用都作為符号引用(Symbilic Renference)儲存在Class檔案的常量池
- 當一個方法要調用其他方法,需要将常量池指向方法的的符号引用轉化為其在記憶體位址中的直接引用。
- 為了将符号引用轉換為調用方法的直接引用
四.StackOverFlowError
- StackOverFlowError:若棧記憶體大小不允許動态擴充,那麼當線程請求棧的深度操作java虛拟機棧的最大深度,就會抛出
StackOverFlowError
- OutOfMemoryError:若棧記憶體大小可以動态擴充,如果虛拟機在動态擴充棧的時候無法申請到足夠的記憶體空間,則抛出
OutOfMemoryError
五.本地方法棧
- 執行Native方法
- 本地方法被執行的時候,在本地方法棧也會建立一個棧幀,用于存放該本地方法的局部變量表、操作數棧、動态連結、出口資訊。
- 方法執行完畢後相應的棧幀也會出棧并釋放記憶體空間,也會出現
和StackOverFlowError
兩種錯誤OutOfMemoryError
六.堆
存放對象執行個體,所有對象執行個體以及數組都在這裡配置設定記憶體
因為是垃圾回收器管理的主要區域,是以也被稱為GC堆(Garbage Collected Heap)
-
java.lang.OutOfMemoryError: GC Overhead Limit Exceeded
-
java.lang.OutOfMemoryError: Java heap space
七.方法區
- 方法區屬于是JVM運作時資料區域的一塊邏輯區域,是各個線程共享的記憶體區域
- 虛拟機要使用一個類時候,需要讀取并解析Class檔案擷取相關資訊,将資訊存入方法區。方法區會存儲已被虛拟機加載的
- 類資訊,字段資訊,方法資訊,常量,靜态變量,即時編譯器編譯後的代碼緩存等資料
八.為什麼要将永久代(PermGen)替換為元空間(MetaSpace)
- 永久代JVM本身設定固定大小上線,無法進行調整,元空間使用直接記憶體
- 元空間裡面存放的是類的中繼資料,由系統空間決定
九.運作時常量池
- Class檔案中除了有類的版本,字段,方法,接口等描述資訊外,還有存放編譯期生成的各種字面量和符号引用的常量池表
十.字元串常量池
- JVM提升性能和減少記憶體消耗針對字元串(String類)專門開辟的一塊區域,避免字元串的重複建立
- JDK1.7 之前,字元串常量池存放在永久代。JDK1.7 字元串常量池和靜态變量從永久代移動了 Java 堆中。
十一.JDK1.7 為什麼要将字元串常量池移動到堆中?
- 永久代GC回收效率低,隻有在Full GC時候才會執行
- java程式通常有大量的被建立的字元串等待回收,将字元串常量池放到堆中,能夠更高效及時地回收字元串記憶體。