使用append时,StringBuilder使用更多内存

时间:2013-07-05 11:03:34

标签: java string stringbuilder string-concatenation

{
    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 14279888 ,但如果我用fileBuff.append("\r\n").append(currLine)替换,我的内存几乎翻了一倍〜 33264440 即可。
有人可以解释原因,我知道String串联也使用StringBuilder吗?

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”)。append(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 个答案:

答案 0 :(得分:5)

使用StringBuilder时,您需要预留空间来为缓冲区添加字符串。这是使用StringBuilder而不是字符串的一个很好的例子,因为你正在使用while循环。

当您使用String时,每次输入如下内容:

String s = s + someOtherString;

您丢弃现有的s字符串并创建一个新字符串而不是s + someOtherString。这意味着你不断需要新的内存来制作连接的字符串,抛出旧的字符串,并将变量的引用放到新的字符串中。

使用StringBuilder,您可以附加到字符串,而无需删除现有部分。

所以是的,它使用了更多的内存,但与使用字符串相比,它在某些情况下非常有效。

换句话说:Stringimmutable objectStringBuilder不是。{/ p>


在您的代码中

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

这与1 {String对象

new String("\r\n" + currLine);相同

你正在使用1追加。

在您的评论中,您说如果使用此内容:

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

这与new String("\r\n");new String(currLine);相同,它们是2个String对象

你的内存几乎翻了一番。这是有道理的,因为你正在进行2次附加,因此使用了两倍的内存。

答案 1 :(得分:1)

我想写这篇关于@JRENs答案的评论,但我没有足够的代表。 2附加的原因需要更多内存http://docs.oracle.com/javase/tutorial/java/data/buffers.html

  

String中不可用的StringBuilder上的主要操作是append()和insert()方法,它们被重载以接受任何类型的数据。每个都将其参数转换为字符串,然后将该字符串的字符附加或插入字符串构建器中的字符序列。

因此,每个追加操作都会创建一个新的String,这就是为什么2个追加(每个循环)占用的内存大约是一个追加量的两倍。