JDK-6239985 : StringBuilder/StringBuffer.toString() copies the character array
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2005-03-14
  • Updated: 2012-01-11
  • Resolved: 2005-03-16
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode)

A DESCRIPTION OF THE PROBLEM :
Before Java5 the StringBuffer implementation has an toString() which shares the character array. It simply set an flag which forces an copy -on-write for the next modification of the character array.

In Java5 this has been changed so that the character array is always cloned on StringBuffer/StringBuilder.toString(). Which slows down the whole code.

I am not sure why it has been changed becuase the old way was logical. Normal usage is to create an StringBuffer and fill it. Then toString() is called and the StringBuffer is no longer been modified.

The old pre-1.5 code StringBuilder and String may share the character array.
StringBuilder looks like:
    public String toString() {
	return new String(this);
    }
and in java.lang.String:
    public String (StringBuffer buffer) {
        synchronized(buffer) {
            buffer.setShared();
            this.value = buffer.getValue();
            this.offset = 0;
            this.count = buffer.length();
        }
    }
so whenever I called StringBuffer.toString(), the returned String shared
the character array with the StringBuffer and thus was somewhat fast.

In 1.5 the behaviour has changed so that StringBuilder/StringBuffer.toString()
always create an copy of the contained character array.
StringBuilder/StringBuffer.toString():
    public String toString() {
        // Create a copy, don't share the array
	return new String(value, 0, count);
    }
String:
    public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        char[] v = new char[count];
        System.arraycopy(value, offset, v, 0, count);
        this.offset = 0;
        this.count = count;
        this.value = v;
    }


The pre-1.5 code suites most needs much better because 
you are creating an StringBuffer and filling it. When calling toString()
the StringBuffer is normally no longer used.
So I wonder if
  String str="test "+int_Variable+" after"
becomes much slower and uses more memory in 1.5 because internally it creates
an StringBuilder and appends the three parts. Afterwards is calls toString()
which creates an copy of the StringBuilder's character array to construct the
new String instance.

REPRODUCIBILITY :
This bug can be reproduced always.
###@###.### 2005-03-14 06:07:11 GMT