首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当使用追加时,StringBuilder使用更多的内存。

当使用追加时,StringBuilder使用更多的内存。
EN

Stack Overflow用户
提问于 2013-07-05 11:03:33
回答 2查看 9.2K关注 0票数 5
代码语言:javascript
复制
{
    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”+ currLine);

代码语言:javascript
复制
      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)

代码语言:javascript
复制
      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长。

EN

回答 2

Stack Overflow用户

发布于 2013-07-05 11:11:00

当使用StringBuilder时,您将预留空间向缓冲区中添加字符串。这是一个使用StringBuilder而不是字符串的好例子,因为您使用的是while循环。

当您使用String时,每次输入类似的内容:

代码语言:javascript
复制
String s = s + someOtherString;

您正在丢弃现有的s字符串,并创建一个新的字符串来代替它,即s + someOtherString。这意味着您经常需要新内存来生成连接字符串,抛出旧字符串,并将变量引用到新字符串。

使用StringBuilder,您可以在不必删除现有部件的情况下追加到字符串中。

所以是的,它使用更多的内存,但是在某些场景中,它比只使用一个字符串更有效。

换句话说:String不可变对象StringBuilder不是。

代码中的

代码语言:javascript
复制
fileBuff.append("\r\n" + currLine);

这与new String("\r\n" + currLine);相同,它是一个字符串对象。

你用的是一个附件。

在你的评论中你说如果你用这个:

代码语言:javascript
复制
fileBuff.append("\r\n").append(currLine);

这与new String("\r\n");new String(currLine);相同,它们是两个字符串对象。

你的记忆力几乎翻了一番。这是有意义的,因为您正在进行2倍的追加,从而使用双倍的内存。

票数 6
EN

Stack Overflow用户

发布于 2013-07-05 11:36:05

我想在@JREN的回复上写这个评论,但是我没有足够的代表。附件2占用更多内存的原因是在这里http://docs.oracle.com/javase/tutorial/java/data/buffers.html

字符串中不可用的StringBuilder上的主要操作是append()和insert()方法,这些方法被重载,以便接受任何类型的数据。每个参数将其参数转换为字符串,然后将该字符串的字符追加或插入到字符串生成器中的字符序列中。

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17487373

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档