Came across a thread dump of a degraded Application server due to high heap utlization. From the face of it realized it was due to one type of report and it fetching lot of records. But they say the devil lies in the detail. If we look at the dump closely we would see following -
at java.util.Arrays.copyOf(Arrays.java:2367)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:415)
at java.lang.StringBuilder.append(StringBuilder.java:132)
The first five lines seem to broadly do the following internally -
1) Initialize a StringBuilder()
Construct a string builder with no characters in it and an initial capacity of 16 characters.
2) Append characters (resulset) to it (In heap the top hogger is character array)
3) Check for capacity by internally - public void ensureCapacity(int minimumCapacity)
Ensures that the capacity is at least equal to the specified minimum. If the current capacity is less than the argument, then a new internal array is allocated with greater capacity. The new capacity is the larger of:
at java.util.Arrays.copyOf(Arrays.java:2367)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:415)
at java.lang.StringBuilder.append(StringBuilder.java:132)
The first five lines seem to broadly do the following internally -
1) Initialize a StringBuilder()
Construct a string builder with no characters in it and an initial capacity of 16 characters.
2) Append characters (resulset) to it (In heap the top hogger is character array)
3) Check for capacity by internally - public void ensureCapacity(int minimumCapacity)
Ensures that the capacity is at least equal to the specified minimum. If the current capacity is less than the argument, then a new internal array is allocated with greater capacity. The new capacity is the larger of:
- The minimumCapacity argument.
- Twice the old capacity, plus 2.
If the minimumCapacity argument is nonpositive, this method takes no action and simply returns.
Parameters: minimumCapacity - the minimum desired capacity.
Reference - https://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html
Surprise Element - In the worst case scenario a StringBuilder can use about required memory *3. That's at that point where the buffer is increased. Right after the copying the usage drops to 2x.
Reference - http://kaioa.com/node/59?wb48617274=B43136AF
What can be done ?
1. Set some initial capacity to a stringbuilder to override the default and reduce instances of expandcapacity and TEST
StringBuilder(int capacity)
Constructs a string builder with no characters in it and an initial capacity specified by the capacity argument.
Parameters: minimumCapacity - the minimum desired capacity.
Reference - https://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html
Surprise Element - In the worst case scenario a StringBuilder can use about required memory *3. That's at that point where the buffer is increased. Right after the copying the usage drops to 2x.
Reference - http://kaioa.com/node/59?wb48617274=B43136AF
What can be done ?
1. Set some initial capacity to a stringbuilder to override the default and reduce instances of expandcapacity and TEST
StringBuilder(int capacity)
Constructs a string builder with no characters in it and an initial capacity specified by the capacity argument.