Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4259569
Votes 1
Synopsis StringBuffer.toString() can cause large memory usage
Category java:classes_lang
Reported Against 1.2
Release Fixed
State 11-Closed, Not a Defect, bug
Priority: 4-Low
Related Bugs 4724129
Submit Date 04-AUG-1999
Description




java -version
java version "1.2"
Classic VM (build JDK-1.2-V, native threads)

java -fullversion
java full version JDK-1.2-V

The problem observed is that the toString() method of
StringBuffer will return a String  customer  which shares the
storage of of the StringBuffer. Subsequent modification of
the StringBuffer causes a copy of the storage. In situations
where the StringBuffer is reused in this fashion, once the
buffer grows to a large size (or is initialized to a specific
size using the StringBuffer(int) constructor) then each String
 customer  created by toString will have a storage size the same
as the (large) StringBuffer size even though very little of
that storage is used by the String. Therefore the practice of
reusing StringBuffer objects (which is a  customer  practice since
the alternative increases  customer  creation/deletion as well
as GC times) is a detriment to memory usage anytime the
StringBuffer's storage grows large compared to some of the
String's that might be created from it.

I believe this shareing behavior of toString goes against the
implicit logistics associated with StringBuffer objects and
can cause very bad problems if StringBuffer's are reused.
The current documentation contains a vague "implementation note"
mentioning the storage sharing without emphasizing the inherent
problem in this. MINIMALLY the documentation should stress what
bad behavior can result. Ideally I think toString should not have
this behavior as it is unexpected and counter-intuitive.
Achieving a storage sharing between String and StringBuffer
 customer  would probably be better served in other ways:

1) a different method other than toString() can be called.
2) add a method 'boolean setShareStorageAllowed(boolean)' could
be added to control toString's behavior.

===Test Case=========
//Test program: bug.java

public class bug {
    // Allocate a large (1 Meg) static buffer that will be reused.
    static StringBuffer buffer = new StringBuffer(1024 * 1024);

    public static void main(String[] args) {
 final int limit = 100;
 int i;
 String[] s = new String[limit];

 for (i=0; i < limit; i++) {
     // Clear buffer then add to it
     buffer.setLength(0);
     buffer.append(" ");

     // Create a string from the buffer and save it.
     s[i] = buffer.toString();

     // Report  customer 
     System.out.println("Created String " + i);
 }
    }
}

Produces the following output:
Created String 0
Created String 1
Created String 2
Created String 3
Created String 4
Created String 5
Created String 6
Created String 7
Created String 8
Created String 9
Created String 10
Created String 11
Created String 12
Created String 13
Created String 14
Created String 15
Created String 16
Created String 17
Created String 18
Created String 19
Created String 20
Created String 21
Created String 22
Created String 23
Created String 24
java.lang.OutOfMemoryError
 at java.lang.StringBuffer.setLength(Compiled Code)
 at bug.main(Compiled Code)
Exception in thread "main"

Due to the unexpected semantics of StringBuffer.toString we have created 24
String objects which each point to 1 Meg of storage even though only a
single character of each is actually used by the String.

Let me know if I can be of further help in describing the problem.
(Review ID: 88266) 
======================================================================
Work Around




Replace calls such as:

buffer.toString()

with

buffer.substring(0, buffer.length())
======================================================================
Evaluation
Reuse of StringBuffers is not recommended, especially now that Hotspot is available. If you feel that you must reuse a StringBuffer, the setLength(0)
call now sets the StringBuffer storage back to the default size.
  xxxxx@xxxxx   1999-10-25
Comments
  
  Include a link with my name & email   

Submitted On 30-JUN-2002
torsten_welches
the evaluation's setLength(0) claim is no longer true as of 
1.4.1 beta... (see bug 4511930)
This should at least be documented in some way.


Submitted On 08-JAN-2003
abrighto
I just ran into this problem and expected to find some kind 
of warning in the StringBuffer javaDoc page, but didn't. It 
wasn't obvious that reusing a StringBuffer could cause the 
application to run out of memory!



PLEASE NOTE: JDK6 is formerly known as Project Mustang