JDK-5039970 : (thread) Excessive memory use preventing creation of threads
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 5.0
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2004-04-29
  • Updated: 2012-10-08
  • Resolved: 2004-06-03
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
5.0 b54Fixed
Related Reports
Relates :  
Description

Name: rmT116609			Date: 04/29/2004


FULL PRODUCT VERSION :
java version "1.5.0-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta-b32c)
Java HotSpot(TM) Client VM (build 1.5.0-beta-b32c, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

EXTRA RELEVANT SYSTEM CONFIGURATION :
512 MB main memory

A DESCRIPTION OF THE PROBLEM :
Application is unable to create more than 1821 threads.

The memory utilization for the JDK 1.5 jvm appears to be about 4 times greater than the 1.4 JDK for the sample program provided.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile then execute the sample program.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Using JDK 1.4.2 I am able to create over 4000 threads.  Using JDK 1.5, the program fails after creating 1821 threads.
ACTUAL -
java.lang.OutOfMemoryError: unable to create new native thread

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
        at java.lang.Thread.start0(Native Method)
        at java.lang.Thread.start(Thread.java:545)
        at JvmThreadTest.run(JvmThreadTest.java:41)
        at JvmThreadTest.main(JvmThreadTest.java:73)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class JvmThreadTest {
  int maxThreads = 100;
  int startedThreads = 0;
  final Object startGate = new Object();
  final Object stopGate = new Object();
  boolean pause = true;
  Runtime runtime = Runtime.getRuntime();
  
  void displayMemoryStats() {
    System.err.println("Runtime.totalMemory(): " + runtime.totalMemory());
    System.err.println("Runtime.maxMemory():   " + runtime.maxMemory());
    System.err.println("Runtime.freeMemory():  " + runtime.freeMemory());
  }
  
  void run(String[] args) {
    if (args.length > 0) maxThreads = Integer.parseInt(args[0]);
    for (int i=0; i < maxThreads; ++i)
    {
      try {
        Thread t = new Thread() {
          public void run() {
            try {
              synchronized(startGate) {
                ++startedThreads;
                startGate.wait();
              }
            } catch(InterruptedException e) { ; /* ignore it */ }
            
            synchronized(stopGate) {
              // signal that we are done
              --startedThreads;

              while(pause) {
                try { stopGate.wait(); }
                catch(InterruptedException e) { ; /* ignore it */ }
              }
            }
          }
        };
        t.setDaemon(true);
        t.start();
      } catch (java.lang.OutOfMemoryError e) {
        System.err.println("" + i  + " threads created");
        displayMemoryStats();
        throw e;
      }
    }
    System.err.println("" + maxThreads + " threads created");
    
    synchronized(startGate) {
      while(startedThreads < maxThreads) {
        try { startGate.wait(50); }
        catch(InterruptedException e) { ; /* ignore it */ }
      }
      System.err.println("" + startedThreads + " threads started");
      displayMemoryStats();
      startGate.notifyAll();  // signal all threads to terminate
    }
    synchronized(stopGate) {
      while(startedThreads > 0) {
        try {stopGate.wait(5); }
        catch(InterruptedException e) { ; /* ignore */ }
      }
      pause = false;
      stopGate.notifyAll();
    }
    System.err.println("" + maxThreads + " threads stopped");
  }
  
  public static void main(String[] args)
  {
    try {
      new JvmThreadTest().run(args);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
/*  Use the following cmd script to execute

setlocal
set JAVA_HOME=c:\java\j2sdk1.4.2_04
set PATH=%java_home%\bin;%path%
javac JvmThreadTest.java
Java -showversion JvmThreadTest 1800
Java -showversion JvmThreadTest 4000

set JAVA_HOME=c:\java\j2sdk1.5.0
set PATH=%java_home%\bin;%path%
javac JvmThreadTest.java
Java -showversion JvmThreadTest 1800
Java -showversion JvmThreadTest 4000


*/
---------- END SOURCE ----------

(Incident Review ID: 260341) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger-rc FIXED IN: tiger-rc INTEGRATED IN: tiger-b54 tiger-rc
08-07-2004

WORK AROUND -XX:+UseDefaultStackSize
08-07-2004

EVALUATION Looks like a JVM issue. Redirecting. ###@###.### 2004-05-11 This reproduces on sparc as well. The real issue is 64 bit vs. 32bit.. If you run in 64 bit the problem "never" appears. Also, if you run with a smaller stack size, say -Xss256k the test runs fine.. This could be an ergonomics issue and choices made when running 32bit jvm.. ###@###.### 2004-05-12 This appears to be windows only - the 1.5.0 VM commits the whole amount of memory specified as 'stack reserve' in the java.exe PE header, whereas it should just have it reserved and commit as needed. It appears that the behavior has not changed significantly on solaris from 1.4.2 to 1.5.0 for the included test case (which would make sense as the code in question is windows-specific) ###@###.### 2004-05-13
13-05-2004