Java 應用運行時,物件建立於不同記憶體區域,各區域特性直接影響效能、生命週期、執行緒安全、GC 行為。理解這五大區域,是調優 JVM、排查 OOM、設計高效能系統的前置知識。
| 區域 | 位置 | 存取速度 | 生命週期 | 主要內容 | 開發者可控性 |
|---|---|---|---|---|---|
| 暫存器 | CPU 內部 | 最快(奈秒級) | 指令執行期間 | 運算中間結果、指標 | 不可控(編譯器/JIT 決定) |
| 堆疊 | RAM,每執行緒私有 | 極快 | 方法呼叫期間 | 基本型別變數、物件參考、方法幀 | 間接可控(區域變數宣告位置) |
| 堆 | RAM,全域共享 | 較快 | GC 管理(不可預知) | 所有 new 出來的物件、陣列 | 可控(new、物件池、逃逸分析) |
| 靜態/常量區 | RAM(方法區/元空間) | 快 | JVM 進程存活期間 | static 欄位、字面常量、類別中繼資料 | 可控(static/final 使用策略) |
| 非 RAM 區 | 磁碟、網路、持久化記憶體 | 慢(毫秒~秒) | 持久化 | 序列化物件、記憶體映射檔、資料庫 | 可控(序列化、持久化框架) |
public void compute() {
int a = 10; // 基本型別直接存堆疊
Object ref = new Object(); // 參考存堆疊,物件在堆
// 方法結束,堆疊幀彈出,a/ref 自動釋放
}
new、反射建立、字面量 String(常量池)最終落地於此。
class Config {
static final String VERSION = "1.0.0"; // 常量池
static DataSource dataSource; // 靜態欄位
static { dataSource = init(); } // 靜態區塊初始化
}
static final;避免濫用 static 導致記憶體洩漏(如靜態集合持有大量物件)。FileChannel.map() 將檔案映射至虛擬記憶體,OS 負責頁面調度。DirectByteBuffer、Netty、BigMemory 繞過堆/GC,適合大快取、低延遲場景。| 場景 | 推薦策略 | 關鍵參數/工具 |
|---|---|---|
| 高頻短命小物件 | 逃逸分析 + 標量替換(無感知) | -XX:+DoEscapeAnalysis (預設開啟) |
| 大量唯讀共享配置 | static final / 常量池 | -XX:StringTableSize (調大字串常量池) |
| 大快取、低延遲 | Off-Heap (DirectByteBuffer/第三方庫) | -XX:MaxDirectMemorySize |
| 超大資料集處理 | Mmap / 分頁載入 | FileChannel.map(), MappedByteBuffer |
| 跨 JVM 物件傳遞 | 序列化 (JSON/Protobuf 推薦) | Jackson, Protobuf, Kryo |
DirectByteBuffer 透過 Cleaner/PhantomReference 觸發釋放,仍有 GC 參與。Java 記憶體模型非黑盒。理解五大區域特性,配合 -XX:+PrintFlagsFinal、JVisualVM、JMC、Arthas 等工具觀測實際行為,才能做出精準調優決策。核心原則:縮短物件生命週期、減少堆分配壓力、善用堆疊/Off-Heap、選擇適合的持久化格式。