JDK-4724129 : Memory leak in use of StringBuffer.toString()
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.4.1,1.4.2
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,solaris_8,windows_2000
  • CPU: generic,x86,sparc
  • Submitted: 2002-07-31
  • Updated: 2003-08-12
  • Resolved: 2003-04-23
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 Other
1.4.1_05 05Fixed 1.4.2Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description
###@###.### 2002-07-31

J2SE Version (please include all output from java -version flag):
java version "1.4.1-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-
Java HotSpot(TM) Client VM (build 1.4.1-rc-b18, mixed mode

Does this problem occur on J2SE 1.3 or 1.4?  Yes / No (pick one)
 No. 1.4 only reports <2MB heap, 
     1.4.1 reports > 13MB heap.
  
Operating System Configuration Information (be specific):
  Win2K SP2
  (Same problem can be reproduced on Solaris 8:
   1.4 -
     Got 174 properties
     Used 3520K
   1.4.1 -
     Got 174 properties
     Used 17512K <----- ~5 times

Hardware Configuration Information (be specific):
  dual 866Mhz Pentium IIIs, 1Gb RAM.

Bug Description:
  Memory leak problem when use Hopper build 18. The application itself 
  basically parses an XML file and has some reflection based code to turn 
  the XML into method calls on an data object.

Steps to Reproduce (be specific):
  1. unjar testcase.jar file
  2. javac *.java
  3. java JDK141Leak

  JDK1.4.1 the app reports it uses > 13Mb heap,
  running same app under 1.4 reports <2Mb heap.

In real life the non-stripped down version parses a bunch of XML 
messages using the same technique. Under 1.4.1 it runs out of memory 
with a 256Mb heap whereas in 1.4 it doesnt even reach 64mb heap size.

  

###@###.### 2002-08-20

More information from the customer:

After further investigation it has been narrowed the problem down to a
call java.lang.StringBuffer.toString().

However, this call has to take place while parsing an XML file, if  
simulate the XML parsing by calling the appropriate methods by hand there 
is no leak.

here is the algorithm used as follow:

Use SAX to parse XML file
   If SAX gets a new element, call startElement() method and append XML
      element name onto XPATH
   If SAX gets new characters, call text() and append the characters into 
      a StringBuffer
   If SAX gets an end element, call endElement() and use the current XPATH 
      to lookup a command pattern and pass it the contents of the current
      StringBuffer. Then remove element name from XPATH.

Its the passing of the contents of the current StringBuffer that is 
causing the leak. Look for the PROBLEM comment in PropertyResponseParser.java

New stripped down code is in the attached jar(JDK141LeakV2.jar).

Name: rmT116609			Date: 08/29/2002


DESCRIPTION OF THE PROBLEM :
Refer to bug ID (4724129)
There is a very significant memory leak in the StringBuffer class. I ran my application using -verbose:gc under j2sdk1.4.0 and under j2sdk1.4.1rc and the memory usage went up dramatically in j2sdk1.4.1rc.

I researched the problem in the bug database and saw something about the bug id referring to StringBuffer class and as a test I replace in the j2sdk1.4.1rc rt.jar file the StringBuffer.class from j2sdk1.4.0 class and it went back to normal.

I did a difference on the two classes and the problem appears in the setLength method where the following code:
	if (count < newLength) {
	    if (shared) copy();
	    for (; count < newLength; count++) {
		value[count] = '\0';
	    }
	} else {
            count = newLength;
            if (shared) {
                if (newLength > 0) {
                    copy();
                } else {
                    // If newLength is zero, assume the StringBuffer is being
                    // stripped for reuse; Make new buffer of default size
                    value = new char[16];
                    shared = false;
                }
            }
        }

was replaced in the 1.4.1rc version with:
	if (count < newLength) {
	    if (shared) copy();
	    for (; count < newLength; count++) {
		value[count] = '\0';
	    }
	} else {
            count = newLength;
            if (shared) copy();
        }

I think this is an IMMEDIATE must fix bug! It would be simple to reverse to the previous code for StringBuffer to solve this simple but huge problem!

(Review ID: 163802)
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.4.1_05 mantis-rc FIXED IN: 1.4.1_05 mantis-rc INTEGRATED IN: 1.4.1_05 mantis-b21 mantis-rc VERIFIED IN: 1.4.1_05
14-06-2004

EVALUATION From Jane, I just duplicated what you saw with 1.4.1 VM and 1.4.0 libraries (finally set myself up with that combo): isher 64 =>java -XXaltjvm=c1-1.4.1 -version java version "1.4.0" Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92) Java HotSpot(TM) Client VM (build 1.4.1-rc-b19, mixed mode) isher 65 =>java -XXaltjvm=c1-1.4.1 -verbose:gc JDK141Leak about to start parsing... [GC 2047K->338K(3520K), 0.0285096 secs] [GC 2386K->391K(3520K), 0.0071823 secs] [GC 2439K->433K(3520K), 0.0052143 secs] [GC 2481K->488K(3520K), 0.0036402 secs] Got 174 properties Used 3520K So I'd suspect the libraries off the top of my head: 1.4.1 libraries + 1.4.1 VM bad behavior 1.4.0 libraries + 1.4.0 VM good 1.4.0 libraries + 1.4.1 VM good ============================================================== No parser changes were made between JDK 1.4.0 and 1.4.1 so it cannot be a problem with the parser code, ie. JAXP. Also, I tried to understand what the code does. Can you provide a simpler test case that parses an XML file? For help on using JAXP, see http://xml.apache.org/~edwingo/jaxp-faq.html. Ultimately, this bug needs to be filed under a different category. ###@###.### 2002-08-14 ======================================================== Submitter provided more info which points to StringBuffer class. ###@###.### 2002-08-21 ========================================================= This is a result of the decision to remove the fix for 4224987 in Hopper, which was done under bug number 4524848. ###@###.### 2002-08-22 The old fix cannot be reinstated because it changes the backing array size in circumstances in which it shouldn't (as well as sometimes when it is desired). Other fixes have been considered but rejected because of performance impact. This will be fixed in Tiger by the removal of String/StringBuffer sharing. ###@###.### 2002-12-05 We have restored the 1.3-1.4 setLength(0) behavior in Mantis as a bridge to the more correct fixes available in Tiger. ###@###.### 2003-04-17
05-12-2002

WORK AROUND Don't reuse StringBuffers. If you do reuse them, check their capacity and make sure that you aren't making tiny Strings from huge StringBuffers. ###@###.### 2002-08-22
22-08-2002