Additional Blogs by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
kohlerm
Employee
Employee
0 Kudos

One important factor when trying to make your application more scalable is to reduce or minimize the memory consumption of your application. From what I see during my daily work, one of the most heavily used classes is java.lang.String. Looking at the typical distribution of a how much memory is consumed in a typical scenario on the SAP Web AS, I usually see around 30-40% spend for Strings only. Also the String class looks simple on the surface, the implementation is really rather complex, which makes it easy to make mistakes.

Lets have a look at the JDK 1.4.2 source for String :

public final class String {//8 bytes overhead for the object private char value[]; //16 bytes minimum + 4 for the reference to the array private int offset; //4 bytes private int count; //4 bytes private int hash = 0; //4 bytes

I added the overhead information for the 32bit Intel SUN JDK. As you can see an object typically has 8 bytes overhead and an int costs 4 Bytes. A char[] has an overhead of 4 Bytes for storing it’s size plus 8 Bytes like each object and needs to by aligned to 8 byte boundaries. Therefore it needs at least 16 bytes.

This means an empty String needs 40 Bytes. So a String object is not that lite.

The char[] might be shared between two or more instances of String. This will reduce the overhead for a String that shares and existing char[] to 24 Bytes. The char[] is only shared when certain functions are called, which can lead to surprising results. Consider the following (simplified, but real world) code fragment :

StringBuffer buffer = new StringBuffer(256); buffer.append("bla"); buffer.append("bla"); String result=buffer.toString(); return result;

Pretty basic (and useless ;)) stuff, you may think. Using a StringBuffer (or StringBuilder on JDK 1.5) is the recommended way to concatenate Strings. + is evil, because it creates lot’s of temporary objects.

But the surprise comes, when you count how much memory the returned string will take. The answer is:

24+2*256+12=548 Bytes

Since the original buffer is not used anymore this is huge waste of memory. If you look at the JDK, you will find that buffer.toString() does not create a new char[], but just very efficiently reuses the char[] from the StringBuffer.

Unfortunately the StringBuffer was much too big for the resulting String.

So please keep the following rule under your pillow :

Try to size your buffer correctly according to the size of the result

In this case you would just use StringBuffer(6).

Interesting enough the following code would also not waste any memory, also it’s slightly less efficient :

StringBuffer buffer = new StringBuffer(256); buffer.append("bla"); buffer.append("bla"); String result=new String(buffer); return new String(result);

The key here is that the constructor new String(result) will automatically create a new char[] if the existing one is to large. This way the JDK tries to ensure that Strings don’t get bigger all the time.

Regards,
Markus

8 Comments