首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 記憶體回收機制深度解析:從對象狀態到 GC 演算法

     編輯:Java 相關知識

前言

Java 的記憶體管理包含記憶體分配(創建對象)與記憶體回收(GC),均由 JVM 自動完成。這降低了開發門檻,避免了 C/C++ 手動管理記憶體的風險。但也導致許多開發者忽視記憶體模型,寫出低效、佔用大的代碼。深入理解 GC,是進階高效 Java 開發的必修課。

一、對象在記憶體中的三種狀態

以有向圖視角(頂點=對象/引用,有向邊=引用關係),從 GC Roots(如棧局部變量、靜態字段、JNI 引用)出發:

  • 可達狀態:至少一條引用鏈從 GC Roots 可達。正常存活。
  • 可恢復狀態:無引用指向,但 finalize() 尚未執行/執行中。若在 finalize() 中重新建立引用,可「復活」為可達。
  • 不可達狀態:finalize() 執行完畢仍無引用。GC 真正回收記憶體。

狀態轉換圖:

二、四種引用類型

注意:覆寫 equals() 必須覆寫 hashCode(),保證「相等對象散列碼相等」,否則 HashMap/HashSet 會失效。

三、GC 演算法核心分類

1. 執行模式

  • 串行:單 CPU,單線程 GC,適合單核/小堆。
  • 並行:多 CPU,多線程同時 GC,吞吐優先,停頓較長。
  • 並發:GC 與應用線程同時運行,停頓極短,但 CPU 開銷大、需預留堆空間。

2. 記憶體整理策略

  • 標記-清除:兩次掃描,不移動對象,產生碎片。
  • 標記-壓縮:標記後移動存活對象消除碎片,需更新引用,成本較高。
  • 複製:將堆劃分兩區,存活對象複製到另一區,無碎片,但浪費 50% 空間。

四、分代收集:新生代 vs 老年代

  • 新生代:Eden + 2 Survivor(From/To)。採用複製算法,回收頻率高、速度快。大多數對象「朝生夕死」。
  • 老年代:存活時間長的對象晉升。採用標記-壓縮,回收頻率低、耗時長。
  • 永久代/元空間:存放 Class、Method 元數據。JDK 8 移至元空間(堆外),默認不回收。動態生成大量類(如 Spring AOP、Hibernate)易導致 OutOfMemoryError: PermGen space / Metaspace。

五、主流垃圾收集器

引用類型創建方式回收時機典型場景
強引用Object obj = new Object();永不回收(寧願 OOM)普通對象持有
軟引用SoftReference<T> ref = new SoftReference<>(obj);記憶體不足時回收緩存(如圖片、網頁)
弱引用WeakReference<T> ref = new WeakReference<>(obj);GC 掃描到即回收WeakHashMap、監聽器
虛引用PhantomReference<T> ref = new PhantomReference<>(obj, queue);回收前入隊列,需配合 ReferenceQueue直接記憶體釋放、回收追蹤
收集器新生代算法老年代算法特點適用場景
Serial複製標記-壓縮單線程,Client 模式默認單核、小堆、嵌入式
Parallel Scavenge並行複製單線程標記-壓縮吞吐優先,可自適應調節批處理、科學計算、Server 默認(JDK 8)
Parallel Old並行複製並行標記-壓縮全並行,JDK 6+多核、追求高吞吐
CMS並行複製並發標記-清除低停頓,碎片整理需 Full GCWeb 應用、響應敏感系統
G1Region 複製Region 標記-壓縮分區、可預測停頓、混合回收大堆(>4G)、JDK 9+ 默認
ZGC / Shenandoah染色指針/讀屏障並發壓縮/轉發亞毫秒停頓,JDK 11/12+ 實驗/產品級超大堆、極低延遲需求

六、記憶體優化小技巧

  1. 優先使用字面量/常量池(String s = "abc";)。
  2. 字符串拼接用 StringBuilder/StringBuffer。
  3. 盡早釋放無用引用(置 null、縮小作用域)。
  4. 慎用 static 持有大對象/集合,延長生命週期。
  5. 熱點數據用緩存框架(Caffeine, Ehcache, Redis),配置過期策略。
  6. 避免覆寫 finalize(),改用 try-with-resources / Cleaner (JDK 9+)。
  7. 需緩存且可丟棄時,考慮 SoftReference。

總結

Java GC 是一套精密的工程體系:分代假設奠定基礎,多種演算法權衡吞吐與停頓,收集器演進適應硬件變遷。作為開發者,理解對象生命週期、引用類型、分代結構、常見收集器特性,配合良好編碼習慣與 JVM 參數調優(-Xms, -Xmx, -XX:+UseG1GC 等),方能駕馭記憶體,構建高性能、穩定的 Java 應用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved