Home » Quick Tips » Java Performance – String, StringBuffer and StringBuilder Memory and Runtime Analysis

2 Flares Twitter 1 Facebook 0 Google+ 1 LinkedIn 0 Email -- Filament.io 2 Flares ×

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.

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 http://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

References

Incoming search terms:

2 Flares Twitter 1 Facebook 0 Google+ 1 LinkedIn 0 Email -- Filament.io 2 Flares ×

About Binu George

2 thoughts on “Java Performance – String, StringBuffer and StringBuilder Memory and Runtime Analysis

  1. Ashish Thakran says:

    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

  2. Mdhar says:

    Good explanation about memory on both String and StringBuffer. Also easy to understand.

Leave a Reply

Your email address will not be published. Required fields are marked *

Paged comment generated by AJAX Comment Page

Google+ Plus Follow on Twitter Like On Facebook Linked Follow

Popular post

JAX-WS Web Services and Clients Java JAX-WS Tutorial: Develop Web Services and Clients (Consumers) Using JAX-WS
jax-ws usernametoken example JAX-WS and Secure Java Web Services using UsernameToken : WS-Security with Metro and WSIT
How to Fix : java.security.cert.CertificateException: No name matching localhost found
JAX-WS exception fault handling example JAX-WS Exceptions and Faults: Annotation, Exception and Fault Handling Examples
SOAP Binding: Difference between Document and RPC Style Web Services

Subscribe to Enterprise Java newsletter
Subscribe
Get Enterprise Java Newsletter

Enter your email and stay on top of things,