2013-07-05 39 views
5
{ 
    StringBuilder fileBuff = new StringBuilder(); 
    long before = getUsedMem(); 
    try { 
    //Open InputStreamReader here 
     while ((currLine = lnr.readLine()) != null) { 
      fileBuff.append("\r\n" + currLine); 
     } 
    //Close streams 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    System.out.println("usedTotal: " + (getUsedMem() - before)); 
} 

private long getUsedMem() { 
    return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); 
} 

運行代碼時好幾次,我得到usedTotal〜,但如果我用fileBuff.append("\r\n").append(currLine)代替我得到幾乎雙倍的內存〜。
請問有人可以解釋原因,因爲我知道String串聯也使用StringBuilderStringBuilder的使用更多的內存時,追加使用

I:fileBuff.append(「\ r \ n」+ currLine);

 62: aload   6 
    64: invokevirtual #16     // Method java/io/LineNumberReader.readLine:()Ljava/lang/String; 
    67: dup   
    68: astore_2  
    69: ifnull  99 
    72: aload_1  
    73: new   #2     // class java/lang/StringBuilder 
    76: dup   
    77: invokespecial #3     // Method java/lang/StringBuilder."<init>":()V 
    80: ldc   #17     // String \r\n 
    82: invokevirtual #8     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    85: aload_2  
    86: invokevirtual #8     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    89: invokevirtual #10     // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    92: invokevirtual #8     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    95: pop   
    96: goto   62 

II fileBuff.append( 「\ r \ n」)。追加(currLine)

 62: aload   6 
    64: invokevirtual #16     // Method java/io/LineNumberReader.readLine:()Ljava/lang/String; 
    67: dup   
    68: astore_2  
    69: ifnull  86 
    72: aload_1  
    73: ldc   #17     // String \r\n 
    75: invokevirtual #8     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    78: aload_2  
    79: invokevirtual #8     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    82: pop   
    83: goto   62 

顯然II路應該使用更少的內存,但事實並非如此。我正在閱讀的文件是50k長。

+2

「*當使用append時,StringBuilder使用更多內存*」。是的,因此每次添加內容時都不會擴展數組。 – johnchen902

+0

@ johnchen902我認爲這應該是一個答案,而不是一個評論... – Puce

+0

@Puce當我沒有找到一個證明沒有答案。 – johnchen902

回答

5

使用StringBuilder時,您正在預留空間來向緩衝區添加字符串。這是使用StringBuilder而不是字符串的一個很好的例子,因爲您使用的是while循環。

當您使用的是String,每次你是這樣的:

String s = s + someOtherString; 

你扔掉你現有s串並創建一個新的去,而不是它是s + someOtherString。這意味着你不斷需要新的內存來創建連接字符串,拋出舊字符串,並將變量的引用放到新字符串中。

使用StringBuilder,您可以追加到您的字符串,而無需刪除現有零件。

所以是的,它使用了更多的內存,但是與僅使用字符串相比,它在某些場景中非常高效。

換句話說:Stringimmutable objectStringBuilder不是。


在您的代碼:

fileBuff.append("\r\n" + currLine); 

這是一樣的new String("\r\n" + currLine);這是您使用1次追加1個String對象

在你的評論說,如果你使用:

fileBuff.append("\r\n").append(currLine); 

這是一樣的new String("\r\n");new String(currLine);這2個String對象

你得到差不多雙倍的內存。這是有道理的,因爲你正在做2x追加,因此使用了兩倍的內存。

+0

嗨,我已經在使用StringBuilder,它比StringBuffer更高效。此外,我得到更高的內存使用率,而不使用字符串連接。如果我使用s = s + someOtherString,我只使用一半的內存。 – CristiL

+0

哦,我把'Stringbuffer'而不是'StringBuilder'對不起!我現在改了它 – JREN

+0

我同意你的理論說,但在實踐中似乎不一樣:fileBuff.append(「\ r \ n」+ currLine)將比fileBuff.append(「\ r \ n「)。append(currLine) – CristiL

1

我想寫這個作爲對@JRENs答案的評論,但我沒有足夠的代表。原因2追加採取更多的存儲器是這裏http://docs.oracle.com/javase/tutorial/java/data/buffers.html

上一個StringBuilder不可用在字符串中的主要操作是追加()和插入()方法,這些方法被重載,以便接受任何類型的數據。每個參數都將其參數轉換爲字符串,然後將該字符串的字符附加或插入到字符串構建器中的字符序列中。

因此,每個附加操作創建一個新的字符串,這就是爲什麼2次追加(每循環)需要大約兩倍多的內存一個追加。

+0

轉換和新字符串實例只是在重載方法的情況下。如果你看看append(String),它不會創建一個新的String實例。 – CristiL