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

JDK 源碼解讀:String 構造器中 originalValue.length > size 發生條件分析

     編輯:Java 相關知識

現象代碼 (JDK 6 String.java)

public String(String original) {
    int size = original.count;
    char[] originalValue = original.value;
    char[] v;
    if (originalValue.length > size) {  // 關鍵判斷
        int off = original.offset;
        v = Arrays.copyOfRange(originalValue, off, off + size);
    } else {
        v = originalValue;
    }
    this.offset = 0;
    this.count = size;
    this.value = v;
}

結論先行

當且僅當 original 由 substring() 產生時,會出現 originalValue.length > size。此時新 String 會複製底層字符數組相關片段,實現內存隔離。

根因:substring() 共享底層 char[]

JDK 6 substring 實現

public String substring(int beginIndex, int endIndex) {
    // 邊界檢查...
    return ((beginIndex == 0) && (endIndex == count)) ? this
        : new String(offset + beginIndex, endIndex - beginIndex, value); // 共享 value 數組
}

String(int offset, int count, char[] value) { // 包私有構造器
    this.value = value;
    this.offset = offset;
    this.count = count;
}

內存佈局示例

String s1 = "hello world";        // value=['h','e','l','l','o',' ','w','o','r','l','d'], offset=0, count=11
String s2 = s1.substring(6);      // value=同 s1.value, offset=6, count=5 ("world")
String s3 = new String(s2);       // 觸發 originalValue.length(11) > size(5) -> 複製 ['w','o','r','l','d']

為什麼要複製?避免內存洩漏

若不複製,s3 仍引用原 11 字符數組,導致 s1 無法被 GC 回收(即使 s1 不再使用)。複製後 s3 持有獨立 5 字符數組,s1 可正常回收。

JDK 7/8/9+ 變化

實際影響與建議

  1. JDK 6 環境:大量 substring 後再 new String() 會觸發複製,有一定 CPU/內存開銷,但避免洩漏。
  2. 性能敏感場景:避免 new String(substring) 模式,直接使用 substring 返回對象,或用 StringBuilder。
  3. 內存診斷:MAT 分析發現大量 char[] 被少量短字符串引用,多為 JDK 6 substring 洩漏特徵。

這段看似多餘的判斷,是 JDK 6 為平衡「substring O(1) 性能」與「防止內存洩漏」的精妙妥協。JDK 7+ 選擇始終複製,簡化邏輯,隨著硬件升級性能損耗可接受。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
版本substring 行為String 構造器邏輯
JDK 6共享 char[] + offset/count檢測共享則複製
JDK 7u6+始終複製新 char[]無需檢測,直接複製
JDK 9+ (Compact Strings)byte[] + coder (LATIN1/UTF16)同 JDK 7,但操作 byte[]