Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most efficient initial capacity size for StringBuilder?

I'm writing lots of stuff to log in bursts, and optimizing the data path. I build the log text with StringBuilder. What would be the most efficient initial capacity, memory management wise, so it would work well regardless of JVM? Goal is to avoid reallocation almost always, which should be covered by initial capacity of around 80-100. But I also want to waste as few bytes as possible, since the StringBuilder instance may hang around in buffer and wasted bytes crop up.

I realize this depends on JVM, but there should be some value, which would waste least bytes, no matter the JVM, sort of "least common denominator". I am currently using 128-16, where the 128 is a nice round number, and subtraction is for allocation overhead. Also, this might be considered a case of "premature optimization", but since the answer I am after is a "rule-of-a-thumb" number, knowing it would be useful in future too.

I'm not expecting "my best guess" answers (my own answer above is already that), I hope someone has researched this already and can share a knowledge-based answer.

like image 673
hyde Avatar asked Nov 13 '12 11:11

hyde


People also ask

What is the initial capacity of the StringBuilder object?

Constructs a string builder that contains the same characters as the specified CharSequence . The initial capacity of the string builder is 16 plus the length of the CharSequence argument.

Which of the following is more efficient StringBuilder?

String is immutable whereas StringBuffer and StringBuilder are mutable classes. StringBuffer is thread-safe and synchronized whereas StringBuilder is not. That's why StringBuilder is faster than StringBuffer.

How can you initialize a StringBuilder to have a capacity of at least 50 characters?

StringBuilder(50) is one of the constructor takes capacity as the parameter and initializes the StringBuilder's capacity. Also you can change the capacity of StringBuilder using the setCapacity(int) method.

How big can a StringBuilder be?

This code creates a StringBuilder object, sbMax , which has a maximum length of 10 characters. Nine characters are appended to this string and then a tenth character is appended without a problem.


2 Answers

Don't try to be smart in this case.

I am currently using 128-16, where the 128 is a nice round number, and subtraction is for allocation overhead.

In Java, this is based on totally arbitrary assumptions about the inner workings of a JVM. Java is not C. Byte-alignment and the like are absolutely not an issue the programmer can or should try to exploit.

If you know the (probable) maximum length of your strings you may use that for the initial size. Apart from that, any optimization attempts are simply in vain.

If you really know that vast amounts of your StringBuilders will be around for very long periods (which does not quite fit the concept of logging), and you really feel the need to try to persuade the JVM to save some bytes of heap space you may try and use trimToSize() after the string is built completely. But, again, as long as your strings don't waste megabytes each you really should go and focus on other problems in your application.

like image 138
JimmyB Avatar answered Oct 24 '22 11:10

JimmyB


Well, I ended up testing this briefly myself, and then testing some more after comments, to get this edited answer.

Using JDK 1.7.0_07 and test app reporting VM name "Java HotSpot(TM) 64-Bit Server VM", granularity of StringBuilder memory usage is 4 chars, increasing at even 4 chars.

Answer: any multiple of 4 is equally good capacity for StringBuilder from memory allocation point of view, at least on this 64-bit JVM.

Tested by creating 1000000 StringBuilder objects with different initial capacities, in different test program executions (to have same initial heap state), and printing out ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed() before and after.

Printing out heap sizes also confirmed, that amount actually allocated from heap for each StringBuilder's buffer is an even multiple of 8 bytes, as expected since Java char is 2 bytes long. In other words, allocating 1000000 instances with initial capacity 1..4 takes about 8 megabytes less memory (8 bytes per instace), than allocating same number of isntances with initial capacity 5...8.

like image 29
hyde Avatar answered Oct 24 '22 09:10

hyde