JDK-4524848 : StringBuffer's setLength() Results in Unneeded GC
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2001-11-08
  • Updated: 2002-03-29
  • Resolved: 2002-02-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.1 hopperFixed
Related Reports
Relates :  
Description

Name: nt126004			Date: 11/08/2001


java version "1.4.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta3-b84)
Java HotSpot(TM) Client VM (build 1.4.0-beta3-b84, mixed mode)


It's a very common Java idiom to append text to a StringBuffer and then return
the corresponding String using the StringBuffer's "toString()" method. When
using a StringBuffer it is common (and good practice) to set the length of the
StringBuffer ahead of time to prevent the StringBuffer from continuously
allocating progressively larger char arrays which must then be GCed.

If you do *not* pre-set the length of a StringBuffer you end up with a default
length of 16 characters.

Here's the problem: If you create a String from a StringBuffer and then you
later set the length of the StringBuffer to zero, the internal size of the
StringBuffer's char[] shrinks down to the default 16 characters, essentially
undoing the capacity setting. Here's an example:


public class Tester {
   static StringBuffer sb = new StringBuffer(1024);

   public static void main(String[] args) {
      System.out.println("length:" + sb.length() +
                         ", capacity:" + sb.capacity());
      buildSomeString();
      System.out.println("length:" + sb.length() +
                         ", capacity:" + sb.capacity());
      buildSomeString(); // capacity shrinks to 16
      System.out.println("length:" + sb.length() +
                         ", capacity:" + sb.capacity());
   }

   static String buildSomeString() {
      sb.setLength(0); // clear out old characters
      System.out.println("after setLength length:" + sb.length() +
                         ", capacity:" + sb.capacity());
      sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
      return sb.toString();
      // return sb.substring(0, sb.length()); // problem goes away...
   }
}


If you run this code you will see that after "buildSomeString()" is called the
second time, the capacity of the StringBuffer has been reduced to 16. This
problem only occurs if a String constructor has been passed a StringBuffer
object as a parameter (which causes the StringBuffer's "shared" flag to be set
to true) *AND* the StringBuffer's length is later set to zero. The coding error
is in the "StringBuffer.setLength()" method.

If you change the return statement in the "buildSomeString()" method to "return
sb.substring(0, sb.length());", the problem goes away.

When a programmer sets the capacity of a StringBuffer, he does so to increase
efficiency. The "setLength()" method sneakily undoes the programmer's good
intentions by setting the capacity back to the default of 16 characters, for no
good reason.
(Review ID: 135229) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: hopper FIXED IN: hopper INTEGRATED IN: hopper VERIFIED IN: hopper
14-06-2004

WORK AROUND Name: nt126004 Date: 11/08/2001 Customer Workaround : Instead of calling StringBuffer.toString(), call StringBuffer.substring(0, sb.length()); ======================================================================
11-06-2004

EVALUATION We will remove the special case for setLength(0) in Hopper to keep this from happening and use some other approach to prevent 4259569 from recurring. ###@###.### 2001-12-04 The problem described in 4259569 can be fixed in Tiger by allowing compaction of a StringBuffer if someone wants to be more memory efficient at the expense of performance. This will occur under bug number 4546734. ###@###.### 2001-12-04
04-12-2001