JDK-8239893 : Windows handle Leak when starting processes using ProcessBuilder
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 11,13.0.2,14,15
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_10
  • CPU: x86_64
  • Submitted: 2020-02-10
  • Updated: 2020-12-10
  • Resolved: 2020-03-06
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.
JDK 11 JDK 13 JDK 15
11.0.11-oracleFixed 13.0.4Fixed 15 b14Fixed
Related Reports
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
Windows 10, JDK 13

A DESCRIPTION OF THE PROBLEM :
When starting processes using java.lang.ProcessBuilder / java.lang.Process, the Windows handle count increases continuously. This leads to the system becoming unresponsive after reaching several hundred thousand handles.

Java 8 and Java 9 are not affected, the regression seems to occur since Java 10.

REGRESSION : Last worked in version 8u241

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test program below. Observe the handle count in den Windows Task Manager by enabling the handle column in the details tab.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Windows handle count stays stable.
ACTUAL -
Windows handle count increases continuously.

---------- BEGIN SOURCE ----------
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class HandleLeak {

	public static void main(String[] args) {
		while( true ) {
			try {
				Process testProcess = new ProcessBuilder("cmd", "/c", "dir").start();
				Thread outputConsumer  = new Thread(() -> consumeStream( testProcess.getInputStream() ) );
				outputConsumer.setDaemon( true );
				outputConsumer.start();
				Thread errorConsumer  = new Thread(() -> consumeStream( testProcess.getErrorStream() ) );
				errorConsumer.setDaemon( true );
				errorConsumer.start();

				testProcess.waitFor();
				System.gc();
			} catch (IOException | InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private static void consumeStream( InputStream inputStream ) {
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(inputStream));
			while( reader.readLine() != null ) {
				;
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if( reader != null ) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
---------- END SOURCE ----------

FREQUENCY : always



Comments
Fix request (13u) Requesting backport to 13u for parity with 11u, applies cleanly.
08-06-2020

Fix Request (11u) Backport to 11u requested. Patch applies cleanly after changing copyright year from 2019 to 2017, exported 11u changeset with original attribution: http://cr.openjdk.java.net/~akasko/jdk11u/8239893/8239893_11u.changeset Test is included with the patch.
25-03-2020

URL: https://hg.openjdk.java.net/jdk/jdk/rev/c81062051951 User: rriggs Date: 2020-03-06 18:53:16 +0000
06-03-2020

The streams need to be closed whether or not they are used by the application that launched the Process.
05-03-2020

Additional Information: I could narrow this down to commit [1] that refactored FileInput-/FileOutputStream cleanup for JDK-8080225 [2]. It was introduced between JDK 10+35 and JDK 10+36, so the latter version is the first one affected by this problem. Since then the Input-/Output- and ErrorStreams that are opened internally are probably not closed properly anymore in Process objects at least on Windows. Since the Process class opens them internally, it is responsible to close them as well, see also the release note [3] and documentation [4] that has been added for JDK-8080225. Third party Java libraries that use the ProcessBuilder/Process classes like jProcesses [5] are affected by this JDK problem as well after updating from JDK 8 to JDK >= 10+36. [1] https://github.com/openjdk/jdk/commit/f29e21abb19380d9aceea04b066f83c7635ffcd8 [2] https://bugs.openjdk.java.net/browse/JDK-8080225 [3] https://www.oracle.com/technetwork/java/javase/10-relnote-issues-4108729.html [4] https://docs.oracle.com/javase/10/docs/api/java/io/FileInputStream.html [5] https://github.com/profesorfalken/jProcesses
28-02-2020

ILW = MHM = P3
25-02-2020

This issue is regression started in 10 ea b36 onwards. 8u241 - Pass 10 ea b35 - Pass 10 ea b36 - Fail <== regression started from here 11.0.7 - Fail 15 ea b09- Fail
25-02-2020