简体   繁体   中英

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 .
Can somebody please explain the reason, as I know String concatenation also uses 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

Clearly #II should use less memory, but it doesn't. The file I am reading is 50k long.

When using StringBuilder you're reserving space to add strings to your buffer. This is a good example to use StringBuilder rather than string because you're using a while loop.

When you're using a String , every time you type something like this:

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 . 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.

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.


In your code:

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

This is the same as new String("\\r\\n" + currLine); which is 1 String object

You're using 1 append.

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"); and new String(currLine); which are 2 String objects

You get almost double the memory. That makes sense because you're doing 2x append, thus using double the memory.

I wanted to write this as a comment on @JRENs answer but I don't have enough rep. The reason 2 appends take more memory is here 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. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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