JDK-4414045 : Leak in ThreadLocal
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.3.0,1.4.0
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,solaris_7
  • CPU: generic
  • Submitted: 2001-02-10
  • Updated: 2001-10-24
  • Resolved: 2001-07-27
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.0 beta2Fixed
Related Reports
Duplicate :  
Description

Name: yyT116575			Date: 02/09/2001


Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Server VM (build 2.0fcs-E, mixed mode)

The keys of ThreadLocals are added to, but never removed from, the
per thread Map.  Even if one explicitly sets the value to null the unique
thread local key is still in the Map.  This can create a problem for long
running threads.

This is a resubmit of a bug which was previously rejected because I did not
provide a test case.  Therefore I'm including the following test case which
will reproduce the problem:

public class test extends Thread {

  public static void main(String[] args) {
    test t = new test();
    t.start();
  }

  private static int counter = 0;

  public void run() {
    System.out.println("Starting");
    try {
      while (true) {
        makeNewThreadLocal();
      }
    } catch (OutOfMemoryError oome) {

      // Print this out in binary format to avoid doing any more allocation
      // after the OutOfMemoryError.  I'm too lazy to write a Hex converter
      // for a test case.

      System.out.print("Managed to allocate and release: '");
      System.out.write((counter >>> 24) & 0xFF);
      System.out.write((counter >>> 16) & 0xFF);
      System.out.write((counter >>>  8) & 0xFF);
      System.out.write((counter >>>  0) & 0xFF);
      System.out.println("' ThreadLocals before running out of memory");

      throw oome;
    }
  }

  // Note that when this method returns both the ThreadLocal and its value
  // will be candidates for collection.  The bug is that even when the
  // ThreadLocal is collected its key remains in the threadLocals Map.

  private void makeNewThreadLocal() {
    ThreadLocal t = new ThreadLocal();
    t.set(new Object());
    t.set(null);
    ++counter;
  }

}


When run this program produces an out of memory error:

Starting
Managed to allocate and release: ' ^Pj^C' ThreadLocals before running out of memory
java.lang.OutOfMemoryError
        <<no stack trace available>>
(Review ID: 116693) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: generic merlin-beta2 FIXED IN: merlin-beta2 INTEGRATED IN: merlin-beta2 VERIFIED IN: merlin-beta2
24-08-2004

EVALUATION This is a performance issue. For certain applications, a switch to WeakHashMap might be warranted, as it does prevent a memory leak in the rare case where an application generates unbounded numbers of ThreadLocal instances. However, it FAR more common that an applications uses very few ThreadLocal instances and "references them" (i.e., calls the get() method) very frequently. Switching from IdentityHashMap to WeakHashMap would make the performance of the common case far, far worse. This is a space-for-time tradeoff - WeakHashMap is better for space, but the advantage only shows up in applications that use huge numbers of ThreadLocals IdentityHashMap is way, way faster than WeakHashMap, so applications using a small, fixed number of ThreadLocals will fair much better with the current implementation. The best of both worlds would be to speed WeakHashMap up to the point where its performance were comparable to that of IdentityHashMap (or perhaps to write a weak variant of IdentityHashMap for internal use). This may be possible for Merlin Beta Refresh or Merlin FCS, but I doubt that it's possible for Merlin Beta. joshua.bloch@Eng 2001-05-04 We have replaced the HashMap with a highly tuned weak identity hash map. The resulting implementation fixes the memory leak and displays significantly iproved performance over the 1.3 (HashMap) implementation. joshua.bloch@Eng 2001-07-25 The OutOfMemoryError is not reproduced in merlin-beta2-b77. ###@###.### 2001-10-23
25-07-2001