簡體   English   中英

為什么我們有字符串池時的字符串重復數據刪除

[英]Why String Deduplication when we have String Pool

字符串重復數據刪除

字符串在任何應用程序中都占用大量內存。每當垃圾收集器訪問String對象時,它都會記錄char數組。 它接受它們的哈希值並將其與對數組的弱引用一起存儲。 一旦找到另一個具有相同哈希碼的String,就會將它們與char進行比較。如果它們匹配,則會修改一個String並指向第二個String的char數組。 然后不再引用第一個char數組,並且可以進行垃圾回收。

字符串池:

java程序使用的所有字符串都存儲在此處。 如果兩個變量初始化為相同的字符串值。 內存中沒有創建兩個字符串,只有一個副本存儲在內存中,兩個副本都指向相同的內存位置。

因此,java已經通過檢查字符串池中是否存在字符串來解決不在堆中創建重復字符串的問題。 那么字符串重復數據刪除的目的是什么?

如果有如下代碼

    String myString_1 = new String("Hello World");
    String myString_2 = new String("Hello World");

即使它們是相同的,也會在內存中創建兩個字符串。 除了這個字符串重復數據刪除很有用之外,我想不出任何其他情況。 顯然我必須遺漏一些東西。 我錯過了什么?

提前致謝

串池適用於加入到它明確,或用作應用常量字符串。 並不適用於應用程序的生命周期中動態創建的字符串。 但是,字符串重復數據刪除適用於所有字符串。

字符串重復數據刪除享有String內置的額外間接級別:

  • 使用字符串池,您只能為兩個相同的字符串返回相同的對象
  • 字符串重復數據刪除允許您擁有共享相同內容的多個不同的String對象。

這轉化為消除了對創建的重復數據刪除的限制:您的應用程序可以繼續創建具有相同內容的新String對象,同時使用非常少的額外內存,因為字符串的內容將被共享。 此過程可以在完全不相關的計划上完成 - 例如,在后台,而您的應用程序不需要太多的CPU資源。 由於String對象的標識不會更改,因此可以從應用程序中完全隱藏重復數據刪除。

編譯時間與運行時間

字符串池是指在編譯時已知的字符串常量

如果您碰巧在運行時檢索(或構造)相同的字符串一百萬次,例如從文件,HTTP請求或任何其他方式讀取它,字符串重復數據刪除將幫助您。

只是為了添加上面的答案,在較舊的VM上,字符串池不是垃圾收集的(現在已經改變了,但不依賴於它)。 它包含在應用程序中用作常量的字符串,因此總是需要它。 如果您不斷將所有字符串放在字符串池中,則可能會很快耗盡內存。 最重要的是,重復數據刪除是一個相對昂貴的過程,如果你知道你只需要很長一段時間的字符串,並且你有足夠的內存。

由於這些原因,字符串不會自動放入字符串池中。 您必須通過調用string.intern()顯式地執行此操作。

除了這個字符串重復數據刪除很有用之外,我想不出任何其他情況。

另外一個(更多)常見的場景是使用StringBuilder StringBuilder類的toString()方法中,它清楚地在內存中創建了一個新實例:

public final class StringBuilder extends AbstractStringBuilder
                                 implements java.io.Serializable, CharSequence
{
    ...

    @Override
    public String toString() {
       // Create a copy, don't share the array
       return new String(value, 0, count);
    }

    ...

}

它的線程安全版本StringBuffer

public final class StringBuffer extends AbstractStringBuilder
                                implements java.io.Serializable, CharSequence
{
   ...

   @Override
   public synchronized String toString() {
       if (toStringCache == null) {
           toStringCache = Arrays.copyOfRange(value, 0, count);
       }
       return new String(toStringCache, true);
   }

   ...
}

在嚴重依賴於此的應用程序中,字符串重復數據刪除可能會減少內存使用量。

來自文檔:

“初始化一個新創建的String對象,使其表示與參數相同的字符序列;換句話說,新創建的字符串是參數字符串的副本。除非需要原始的顯式副本,否則使用此構造函數因為字符串是不可變的,所以不必要。“

所以我的感覺說,String類中的這個構造函數通常不像你上面使用的那樣需要。 我想這個構造函數僅僅是為了完整性而提供的,或者如果你不想共享那個副本(現在有點不必要,請參考這里我要討論的內容)但是其他構造函數也很有用,比如從char數組中獲取一個String對象等等..

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM