简体   繁体   English

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

[英]StringBuilder uses more memory when append is used

{
    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();
}

While running the code several times, I get usedTotal ~ 14279888 , but if I replace with fileBuff.append("\\r\\n").append(currLine) I get almost double the memory ~ 33264440 . 在运行代码几次时,我得到usedTotal ~ 14279888 ,但是如果我用fileBuff.append("\\r\\n").append(currLine)替换fileBuff.append("\\r\\n").append(currLine)我的内存几乎fileBuff.append("\\r\\n").append(currLine)了一倍~ 33264440
Can somebody please explain the reason, as I know String concatenation also uses StringBuilder ? 有人可以解释原因,因为我知道String连接也使用StringBuilder

I: fileBuff.append("\\r\\n" + currLine); 我: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) 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

Clearly #II should use less memory, but it doesn't. 显然#II应该使用更少的内存,但事实并非如此。 The file I am reading is 50k long. 我正在阅读的文件是50k长。

When using StringBuilder you're reserving space to add strings to your buffer. 使用StringBuilder您需要预留空间来向缓冲区添加字符串。 This is a good example to use StringBuilder rather than string because you're using a while loop. 这是使用StringBuilder而不是string的一个很好的例子,因为你正在使用while循环。

When you're using a String , every time you type something like this: 当你使用String ,每次输入如下内容:

String s = s + someOtherString;

You're throwing away your existing s string and creating a new one to go instead of it which is s + someOtherString . 你丢弃现有的s字符串并创建一个新字符串而不是s + someOtherString This means that you're constantly needing new memory to make the concatenated string, throw the old one out, and put the reference of your variable to your new string. 这意味着你经常需要新的内存来制作连接的字符串,抛出旧的字符串,并将变量的引用放到新的字符串中。

With a StringBuilder you can append to your string without having to remove the existing part. 使用StringBuilder您可以附加到字符串,而无需删除现有部分。

So yes, it uses more memory, but it's very efficient in some scenario's compared to using just a string. 所以是的,它使用了更多的内存,但与仅使用字符串相比,它在某些情况下非常有效。

In other words: String is an immutable object and a StringBuilder isn't. 换句话说: String是一个不可变对象,StringBuilder则不是。


In your code: 在你的代码中:

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

This is the same as new String("\\r\\n" + currLine); 这与new String("\\r\\n" + currLine); which is 1 String object 这是1个String对象

You're using 1 append. 你正在使用1追加。

In your comment you say that if you use this: 在你的评论中你说如果你使用这个:

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

This is the same as new String("\\r\\n"); 这与new String("\\r\\n"); and new String(currLine); new String(currLine); which are 2 String objects 这是2个String对象

You get almost double the memory. 你几乎翻了一倍的记忆。 That makes sense because you're doing 2x append, thus using double the memory. 这是有道理的,因为你正在进行2次附加,因此使用了两倍的内存。

I wanted to write this as a comment on @JRENs answer but I don't have enough rep. 我想写这篇关于@JRENs答案的评论,但我没有足够的代表。 The reason 2 appends take more memory is here http://docs.oracle.com/javase/tutorial/java/data/buffers.html 2个追加的原因需要更多内存,请访问http://docs.oracle.com/javase/tutorial/java/data/buffers.html

The principal operations on a StringBuilder that are not available in String are the append() and insert() methods, which are overloaded so as to accept data of any type. String中不可用的StringBuilder上的主要操作是append()和insert()方法,它们被重载以接受任何类型的数据。 Each converts its argument to a string and then appends or inserts the characters of that string to the character sequence in the string builder. 每个都将其参数转换为字符串,然后将该字符串的字符追加或插入字符串生成器中的字符序列。

So, each append operation creates a new String, which is why 2 appends (per loop) takes roughly twice as much memory as one append. 因此,每个追加操作都会创建一个新的String,这就是为什么2个追加(每个循环)占用的内存大约是一个追加的两倍。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM