JDK-4637640 : Memory leak due to String.substring() implementation
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_nt
  • CPU: x86
  • Submitted: 2002-02-14
  • Updated: 2005-07-26
  • Resolved: 2002-02-14
Related Reports
Duplicate :  
Relates :  
Description
Name: rmT116609			Date: 02/13/2002


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.0-b92, mixed mode)

and also

java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0)
Classic VM (build 1.3.0, J2RE 1.3.0 IBM build co130-20010925 (JIT enabled: jitc)
)

DESCRIPTION OF THE PROBLEM :

String.substring() and StringBuffer.substring() attempt to improve performance (and reduce the memory footprint) by sharing the underlying char[] across various Strings.

However, a problem arises in the following scenerio:

1) Create a huge temporary StringBuffer
2) Extract short strings using substring() and place them in long-term storage (in a table of some sort)
3) Delete the StringBuffer, assuming it will be garbage-collected

However, due to implementation issues the huge StringBuffer will not be garbage collected so long as the substrings extracted from it live. This poses a problem and can potencially lead to huge memory leaks.

I don't necessarily have a solution, but I *did* want to point out this problem. This lead to a memory leak of 10MB/second on my sample app and I only managed to track down the problem by looking at the sources in String.java.

Upon forcing a String copy via getChars(), the memory leak disappeared and the huge buffer was being garabage collected properly.

The API should handle this problem better or at the very least provide extensive documentation on this topic.

This bug can be reproduced always.

Source:

class Test{

public static void main(String a[]) {

 String [] buffer = new String[10000];
 for (int i = 0; i < 10000; i++) 
 {
  buffer[i] = new String(new char[10000000]).substring(0, 1);
 }

}
}

The above is really bad coding, but it demonstrates what is happening. The above will keep references to all char[10000000] instances for as long as buffer[] lives.

CUSTOMER WORKAROUND :
Copy substrings manually; however this makes the code JVM-specific.
(Review ID: 139509) 
======================================================================