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

Java 8 字串去重:G1 GC 新特性原理、啟用與實測

     編輯:Java 相關知識

背景

JDK 8u20 引入 String Deduplication,針對 Java 應用中佔堆 20-30% 的 String 物件,透過共享底層 char[]/byte[] 降低記憶體佔用。僅支援 G1 GC,預設關閉。

運作原理

  1. GC 掃描存活 String 物件,計算其值陣列雜湊並存入弱參考表。
  2. 發現雜湊碰撞時,逐字元比對內容。
  3. 完全相同則將其中一個 String 的 value 欄位指向另一個的陣列。
  4. 原陣列無強參考 → 下輪 GC 回收。
  5. 優化:曾比對無重複的 String 會被標記「冷卻」,一段時間不再檢查。

啟用參數

-XX:+UseG1GC
-XX:+UseStringDeduplication
-XX:+PrintStringDeduplicationStatistics  # 列印去重統計

實測程式碼

public class StringDedupDemo {
    private static final List HOLDER = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        int iter = 0;
        while (true) {
            for (int i = 0; i < 100; i++)
                for (int j = 0; j < 1000; j++)
                    HOLDER.add(new String("String " + j)); // 大量重複字串
            System.out.println("Survived Iteration: " + ++iter);
            Thread.sleep(100);
        }
    }
}

測試結果對比 (Xmx256m)

配置存活輪數備註
G1 + 無去重~30OOM 崩潰
G1 + 啟用去重持續運行記憶體穩定,GC 日誌顯示去重量

GC 日誌範例

[String Deduplication] 
  Scanned 123456 objects, 
  Deduplicated 110000 (89.1%), 
  Saved 45.2 MB (12.3% heap), 
  12.5 ms (avg 0.1 us/obj)

字串去重 vs 字串駐留

特性String DeduplicationString.intern() / 常量池
範圍僅共享 value 陣列共享整個 String 實例
觸發時機G1 GC 並發標記階段呼叫 intern() 或編譯期常量
適用對象動態產生、生命週期長的 String固定常量、手動驅動
記憶體節省陣列大小 × 重複數整個物件頭 + 陣列

適用場景與限制

  • ✅ 大量重複業務代碼、訊息、URL、JSON 片段的長期存活物件。
  • ⚠️ 僅 G1 GC,且會增加 GC 停頓 (掃描/比對成本),需實測評估吞吐量影響。
  • ⚠️ JDK 9+ Compact Strings (Latin-1/UTF-16) 已大幅降低單字串記憶體,去重效益遞減。
  • ❌ 短命物件 (Eden 區死亡) 不會被去重。

Java 8u20+ 專案若使用 G1 GC 且觀察到大量重複 String 佔用堆,建議開啟 -XX:+UseStringDeduplication 並觀察 GC 日誌統計,若節省 > 10% 堆且停頓增長可接受,即可長期啟用。

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