執行時資料區-方法區
阿新 • • 發佈:2021-12-08
目錄
概括
- 方法區是在虛擬機器啟動時建立的
- 方法區是所有 Java 虛擬機器執行緒之間共享的
- 它儲存每個類的結構,例如執行時常量池、欄位和方法資料,以及方法和建構函式的程式碼,包括在類和介面初始化以及例項初始化中使用的特殊方法
- 方法區可以是固定大小,也可以根據計算需要進行擴充套件,如果不需要較大的方法區,可以進行收縮。方法區的記憶體不需要是連續的
- 在jdk8以前,方法區稱為永久代,jdk8及以後稱為元空間
- 元空間使用的是本地記憶體
設定方法區大小
- jdk8以前:-XX:PermSize設定永久代初始大小、-XX:MaxPermSize設定永久代最大可分配空間
- jdk8及以後:-XX:MetaspaceSize設定元空間初始大小、-XX:MaxMetaspaceSize設定元空間最大可分配空間
如何解決OOM
- 通過記憶體映像工具對dump出來的堆儲存快照進行分析,知道是出現的記憶體洩露還是記憶體溢位
- 如果是記憶體洩漏,可進一步通過工具檢視洩漏物件到cc Roots 的引用鏈。於是就能找到洩漏物件是通過怎樣的路徑與GC Roots相關聯並導致垃圾收集器無法自動回收它們的。掌握了洩漏物件的型別資訊,以及GC Roots引用鏈的資訊,就可以比較準確地定位出洩漏程式碼的位置
- 如果不是記憶體洩漏,檢視堆空間是否可以調大,檢查是否存在生命週期過長的物件,嘗試減少程式執行期的記憶體消耗
執行時常量池
- 一個執行時常量池是一個類或一個介面在位元組碼檔案中常量池的表現
- 它包含多種型別的常量、從編譯時已知的數值字面量、在執行時解析的方法和欄位引用
- 執行時常量池的功能類似於傳統程式語言的符號表
- 每個執行時常量池都是從Java虛擬機器的方法區分配的
- 類或介面的執行時常量池是在Java虛擬機器建立類或介面時構造的
方法區演進細節
- jdk1.7以前:有永久代,靜態變數存放在永久代上
- jdk1.7:有永久代,字串常量池、靜態變數移除,儲存在堆中
- jdk8及以後:無永久代,型別資訊、欄位、方法、常量儲存在本地記憶體的元空間,但是字串常量池、靜態變數仍然在堆中
永久代為什麼被替換?
- 為永久代設定空間大小很難確定
- 對永久代調優很困難
GC
方法區的垃圾收集主要回收兩部分內容:常量池中廢棄的常量和不再使用的型別。方法區中的常量池主要存放兩類常量:字面量和符號引用.只要常量池中的常量沒有被任何引用,就會被回收
字面量(literal)是用於表達原始碼中一個固定值的表示法(notation)。
符號引用包含以下三類常量:
- 類和介面的全限定名
- 欄位的名稱和描述符
- 方法的名稱和描述符
判斷一個類是否屬於"不再使用的類"需要滿足以下三個條件,這樣Java虛擬機器允許對這樣的類進行回收 - 該類所有的例項都已經被回收
- 載入該類的類載入器已經被回收
- 該類對於的java.lang.Class物件沒有在任何地方被引用