關於 Java 內存模型中「方法區」的存儲內容與管理機制,很多開發者感到困惑。本文結合 JDK 8+ 變更(永久代 → 元空間),系統梳理方法區的核心職責。
方法區存儲什麼?
根據 JVM 規範,方法區是**各線程共享**的內存區域,主要存儲:
- 類元信息: 類的完整有效名、修飾符、繼承關係、接口、註解、泛型簽名等。
- 運行時常量池: 編譯期生成的字面量、符號引用(類/方法/字段符號引用),以及 `String.intern()` 產生的字符串對象引用(JDK 7+ 字符串對象移至堆)。
- 字段/方法信息: 名稱、描述符、修飾符、字節碼、異常表、行號表、本地變量表等。
- JIT 編譯後的代碼緩存: 即時編譯器生成的機器碼。
- 靜態變量: `static` 修飾的字段(注意:JDK 7 將靜態變量對象移至堆,方法區僅存引用)。
JDK 8 關鍵變更:永久代 → 元空間
| 特性 | 永久代 (JDK 7-) | 元空間 (JDK 8+) |
| 存儲位置 | 堆內存連續區域 | 本地內存 |
| 大小限制 | -XX:MaxPermSize (固定) | -XX:MaxMetaspaceSize (默認無上限,受限於物理內存) |
| 字符串常量/靜態變量 | 存放在永久代 | 移至 Java 堆 |
| GC 回收 | 困難,易 OOM | 由類卸載觸發,更靈活 |
內存管理與調優參數
- -XX:MetaspaceSize:初始元空間大小(觸發首次 GC 閾值)。
- -XX:MaxMetaspaceSize:最大元空間大小,**生產環境建議設置**,防止佔盡物理內存導致系統 OOM Killer 殺進程。
- -XX:MinMetaspaceFreeRatio / MaxMetaspaceFreeRatio:GC 後最小/最大空闲比例,控制擴縮容。
- 類卸載條件: 該類所有實例被回收、加載該類的 ClassLoader 被回收、該類 `java.lang.Class` 對象無引用。可用 `-Xlog:class+unload` 監控。
常見問題排查
- Metaspace OOM: 通常由動態生成大量類(如 CGLIB、JSP、Groovy、大量代理類)且 ClassLoader 不被回收導致。排查:`jcmd VM.class_histo` / `jmap -histo:live ` 統計類數量;檢查 ClassLoader 洩漏。
- 類加載死鎖: 多線程並發加載同一類觸發 `` 鎖競爭,JVM 內部有鎖機制避免重複加載,但自定義 ClassLoader 需注意同步。
總結
方法區(元空間)是**類級別數據的倉庫**,不存放方法執行時的局部變量(那在棧幀)。理解其從永久代到元空間的演進,有助於解決生產環境的 Metaspace OOM 與類洩漏難題。
- 上一篇文章: 華為手機 SecurityException: Permission denial 解決:補全 WRITE_SETTINGS 權限
- 下一篇文章: 手機通訊錄雲端備份:增量同步核心邏輯與頭像比對策略
Copyright ©
程式碼之家 All Rights Reserved