We normally use many string instances in our applications. As we know String objects are immutable and their values cannot be changed after they are created. If you intend to use a string object that is dynamic, then StringBuffer or StringBuilder should be your choice. This is because both are mutable. String always creates a new object when you try to update the same.
Table of Contents
Difference between Java String, StringBuffer and StringBuilder Classes
Java uses a special mechanism while concatenating Strings using concatenation operator ( + ). String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method. The conversion is implemented using toString() method of Object class. For example see the operation below.
String newString = “part1” + “part2”;
The java will compile the above statement to,
String newString = new StringBuffer().append("part1").append("part2").toString();
But what about string concatenation logic inside a loop ? If you use a String object to concatenate inside a loop, it will generate intermediate string objects in memory. That is clear instance of wastage of memory. But if you use StringBuffer or StringBuilder you can utilize append () method that simply updates the internal buffer of respective object.
A loop like the following not only takes extra heap memory by creating extra objects but the processing time also will be higher.
String s=""; for(int i=1;i<50000;i++){ s=s+i; }
But the same loop when you rewrite using StringBuffer has far better performance.
StringBuffer s= new StringBuffer();; for(int i=1;i<50000;i++){ s.append(i); }
You can also use StringBuilder that performs even better because StringBuffer is little more heavy as all its methods are synchronized.StringBuilder is not thread safe and offer better performance compared to StringBuffer.
StringBuilder s= new StringBuilder(); for(int i=1;i<50000;i++){ s.append(i); }
Memory Usage and Performance Comparison test of String, StringBuffer and StringBuilder
Let us see a sample program, which prints the heap memory usage to check all the above examples. The example also prints the time taken to complete each operation.
/* * @(#)StringMemoryTest.java * @author Binu George * Globinch.com * copyright https://www.globinch.com. All rights reserved. */ package test; /** * The StringMemoryTest class. * * @author Binu George * @since 2013 * @version 1.0 */ public class StringMemoryTest { private static final int MBinBytes = 1048576; private static final int KBinBytes = 1024; /** * */ public StringMemoryTest() { // TODO Auto-generated constructor stub ; } /** * Perform GC */ private void performGC() { for (int i = 0; i < 10; i++) { System.gc(); try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } /** * Get the memory used value. * * @return long */ private long memoryUsed() { return ((Runtime.getRuntime().totalMemory() / KBinBytes) - (Runtime .getRuntime().freeMemory() / KBinBytes)); } /** * Method to test String object memory consumption in a BIG loop */ public void testStringMemory() { System.out .println("Initial Total memory in Java virtual machine in KBs=" + Runtime.getRuntime().totalMemory() / KBinBytes); System.out .println("Initial Free memory in Java virtual machine in KBs=" + Runtime.getRuntime().freeMemory() / KBinBytes); long initialmemory = memoryUsed(); long startTime = System.currentTimeMillis(); String s = ""; for (int i = 1; i < 50000; i++) { s = s + i; } long stopTime = System.currentTimeMillis(); long elapsedTime = stopTime - startTime; System.out .println("Time taken to complete the process :" + elapsedTime); System.out.println("Memory used by String in KBs=" + (memoryUsed() - initialmemory)); s = null; performGC(); System.out.println("Free Memory after GC in KBs=" + Runtime.getRuntime().freeMemory() / KBinBytes); } /** * Method to test StringBuilder object memory consumption in a BIG loop */ public void testStringBuilderMemory() { System.out .println("Initial Total memory in Java virtual machine in KBs=" + Runtime.getRuntime().totalMemory() / KBinBytes); System.out .println("Initial Free memory in Java virtual machine in KBs=" + Runtime.getRuntime().freeMemory() / KBinBytes); long initialmemory = memoryUsed(); long startTime = System.currentTimeMillis(); StringBuilder s = new StringBuilder(); for (int i = 1; i < 50000; i++) { s.append(i); } long stopTime = System.currentTimeMillis(); long elapsedTime = stopTime - startTime; System.out .println("Time taken to complete the process in MilliSeconds:" + elapsedTime); System.out.println("Memory used by StringBuilder in KBs=" + (memoryUsed() - initialmemory)); s = null; performGC(); System.out.println("Free Memory after GC in KBs=" + Runtime.getRuntime().freeMemory() / KBinBytes); } /** * Method to test StringBuffer object memory consumption in a BIG loop */ public void testStringBufferMemory() { System.out .println("Initial Total memory in Java virtual machine in KBs=" + Runtime.getRuntime().totalMemory() / KBinBytes); System.out .println("Initial Free memory in Java virtual machine in KBs=" + Runtime.getRuntime().freeMemory() / KBinBytes); long initialmemory = memoryUsed(); long startTime = System.currentTimeMillis(); StringBuffer s = new StringBuffer(); for (int i = 1; i < 50000; i++) { s.append(i); } long stopTime = System.currentTimeMillis(); long elapsedTime = stopTime - startTime; System.out .println("Time taken to complete the process :" + elapsedTime); System.out.println("Memory used by StringBuffer in KBs=" + (memoryUsed() - initialmemory)); s = null; performGC(); System.out.println("Free Memory after GC in KBs=" + Runtime.getRuntime().freeMemory() / KBinBytes); } /** * Main class * * @param args */ public static void main(String[] args) { System.out.println("Initial Max memory in Java virtual machine in KBs=" + Runtime.getRuntime().maxMemory() / KBinBytes); StringMemoryTest memoryTest = new StringMemoryTest(); System.out.println(" ........\nString memory test\n"); memoryTest.testStringMemory(); System.out.println(" ........\nStringBuffer memory test\n"); memoryTest.testStringBufferMemory(); System.out.println(" ........\nStringBuilder memory test\n"); memoryTest.testStringBuilderMemory(); } }
The output is given below. Just compare the memory consumed by String objects and that of StringBuffer and StringBuilder. String operation consumes arround 2674kb of memory while StringBuffer and StringBuilder consumes 1199 kilobytes. There is a huge difference in time taken to complete the process also. String operation took 23113 milliseconds while StringBuffer took 6 milliseconds and StringBuilder took 5 milliseconds.
Please note that, the result values are approximate and varies based on the machine configuration and JVM memory parameters.
Initial Max memory in Java virtual machine in KBs=253440 ........ String memory test Initial Total memory in Java virtual machine in KBs=15872 Initial Free memory in Java virtual machine in KBs=15590 Time taken to complete the process :23113 Memory used by String in KBs=2674 Free Memory after GC in KBs=15792 ........ StringBuffer memory test Initial Total memory in Java virtual machine in KBs=15936 Initial Free memory in Java virtual machine in KBs=15792 Time taken to complete the process :6 Memory used by StringBuffer in KBs=1199 Free Memory after GC in KBs=15792 ........ StringBuilder memory test Initial Total memory in Java virtual machine in KBs=15936 Initial Free memory in Java virtual machine in KBs=15792 Time taken to complete the process in MilliSeconds:5 Memory used by StringBuilder in KBs=1199 Free Memory after GC in KBs=15792
String is an immutable class while StringBuilder & StringBuffer are mutable classes. StringBuffer is synchronized while StringBuilder is not.
Below link can be useful to find more differences between String, StringBuffer & StringBuilder
Difference between String, StringBuffer and StringBuilder
Good explanation about memory on both String and StringBuffer. Also easy to understand.
valuable knowledge about String keep it up dear ..