JDK-4310930 : Need memory-saving conversion from StringBuffer to String
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.3.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2000-02-08
  • Updated: 2002-03-12
  • Resolved: 2002-03-12
Related Reports
Duplicate :  
Description

Name: krT82822			Date: 02/08/2000


E:\JavaDev\Prototypes>java -version
java version "1.3beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3beta-O)
Java(TM) HotSpot Client VM (build 1.3beta-O, mixed mode)

A customer recently complained to me that my Java program took way too much
memory while running.  I started exploring my code and found (among other
things) that conversion from a StringBuffer to a String can waste memory.

The way I understand your code, a call to StringBuffer.toString() calls the
String constructor that passes the StringBuffer as the argument.  That
constructor, to save memory & unnecessary copying, doesn't copy the array of
characters from StringBuffer.  Instead, it takes a reference to those characters
and then marks the StringBuffer as "shared".  Then, future references to
StringBuffer that attempt to modify it result in a copy of the StringBuffer's
character array being made.  Pretty cool, right?  The problem is, what if the
StringBuffer's character array is too big for the string it's holding?  Here's a
simplistic example:

StringBuffer sb = new StringBuffer(5000);
sb.append("Hi");
String hi = sb.toString();
sb.append(" there");

If you look at the string hi, you'll notice that it's being held in an array of
size 5000.

This problem can be worked around fairly well if you've got an idea ahead of
time what the length of the string will be, but if you don't, or if you don't
have control of the StringBuffer (eg BufferedReader.readLine()) you can't set
the length to anything appropriate.

What I would like to see is either a method added to StringBuffer such as
copyToString() that would look like:
public String copyToString() {
  return new String(value, 0, count);
} //Ends method copyToString

Alternatively, you could have a flag that the user sets to trigger the behavior
of the toString() method.

I realize that this is asking a lot - a change to a very important API - but
this memory wasting is absolutely killing me.  I may very well end up
implementing workaround #2 (below) soon to save enough space to make my program
workable.
(Review ID: 100975) 
======================================================================

Comments
WORK AROUND Name: krT82822 Date: 02/08/2000 1. Write a method that works like this: public String copyBufferToString(StringBuffer sb) { synchronized(sb) { char[] array = new char[sb.length()]; sb.getChars(0, sb.length(), array, 0); return new String(array); } //Ends synchronized } //Ends method copyBufferToString The problem with this solution is that a third unnecessary character array gets created. This leaves you at the mercy of the garbace collector to clean up the memory allocation. 2. Create my own StringBuffer. Not too appealing. Nor am I certain that it would be legal given all the digging I've already done into your code to figure this out. ======================================================================
11-06-2004

EVALUATION I am quite surprised by this behavior. I would expect toString to result in only the storage needed remaining allocated, and think most users would expect this as well. william.maddox@Eng 2000-02-11 Adding StringBuffer.trimToSize will allow users to select the more memory efficient side of the speed vs memory spectrum of StringBuffers becoming Strings. See 4546734. ###@###.### 2002-03-12
12-03-2002