ADDITIONAL SYSTEM INFORMATION :
OS: Windows 10, Windows Server 2022.
OpenJDK: 11.0.22.0, 11.0.19, 11.0.18
A DESCRIPTION OF THE PROBLEM :
A sample Java program to create 500 threads and wait for them to end gracefully - would leak 2500+ event handles and few Thread handles consistently. 100% reproducible, sample code attached herewith.
The standalone sample code just demonstrates the handle leaks I see in on of our production code java services.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Note down a java programs handle count (using handle.exe / windbg.exe) before it creates multiple threads.
2. Wait for the threads to complete gracefully.
3. Note the handle count - I can see several windows Event object handles leaked.
Sample code attached below.
The program prints the PID and waits before creating 500 threads so user can run tools like sysinternals handle.exe or windbg to capture handle count, then user can press <Enter> to proceed with 500 threads creation, waits for graceful thread completion and pauses for user input during when user can run handle tool again to capture handle count / delta.
It will be evident 2500+ Event handles, and few Thread handles are leaked in this execution. I waited for hours/days - still handles are not released.
Code is attached to reproduce this issue.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No handle leaks.
ACTUAL -
PROGRAM OUTPUT:
Process ID: 11748
Note process handle count using tools - handle/windbg, press Enter to create 500 threads.
Starting 500 threads...
Thread 73 created, sleeping for 15 seconds.
Thread 151 created, sleeping for 15 seconds.
Thread 45 created, sleeping for 15 seconds.
Thread 150 created, sleeping for 15 seconds.
.....
Thread 453 created, sleeping for 15 seconds.
500 threads stopped, check handle count.
Press Enter to exit.
Process ID: 11748
Note process handle count using tools - handle/windbg, press Enter to create 500 threads.
HANDLE TOOLS OUTPUT:
(Mon 04/22/2024 11:02:23.97) X:\Tools\SysinternalsSuite>handle -s -p 11748
Handle v3.5
Copyright (C) 1997-2012 Mark Russinovich
Sysinternals - www.sysinternals.com
Handle type summary:
ALPC Port : 1
Desktop : 1
Directory : 2
EtwRegistration : 68
Event : 125
File : 13
IoCompletion : 3
IRTimer : 4
Key : 11
Mutant : 2
Section : 2
Semaphore : 34
Thread : 19
TpWorkerFactory : 2
WaitCompletionPacket: 6
WindowStation : 2
Total handles: 295
(Mon 04/22/2024 11:02:25.36) X:\Tools\SysinternalsSuite>handle -s -p 11748
Handle v3.5
Copyright (C) 1997-2012 Mark Russinovich
Sysinternals - www.sysinternals.com
Handle type summary:
ALPC Port : 1
Desktop : 1
Directory : 2
EtwRegistration : 68
Event : 2640
File : 13
IoCompletion : 3
IRTimer : 4
Key : 11
Mutant : 2
Section : 2
Semaphore : 34
Thread : 23
TpWorkerFactory : 2
WaitCompletionPacket: 6
WindowStation : 2
Total handles: 2814
---------- BEGIN SOURCE ----------
import java.util.ArrayList;
import java.util.Scanner;
public class Main implements Runnable {
public static void main(String[] args) {
System.out.println("Process ID: " + ProcessHandle.current().pid()) ;
System.out.println("Note process handle count using tools - handle/windbg, press Enter to create 500 threads.");
try (var inp = new Scanner(System.in)) {
inp.nextLine();
var task = new Main();
task.startThreads();
task.waitForThreadsToComplete();
System.out.println("Press Enter to exit.");
inp.nextLine();
}
}
ArrayList<Thread> thread_list = new ArrayList<Thread>();
static int thread_count = 0;
public void startThreads() {
System.out.println("Starting 500 threads...");
for (int i = 0; i < 500; ++i) {
Thread t = new Thread(this);
t.start();
thread_list.add(t);
}
System.out.println("500 threads started...");
}
public void waitForThreadsToComplete() {
System.out.println("Waiting for 500 threads to stop...");
thread_list.forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
System.out.println("500 threads stopped, check handle count.");
}
@Override
public void run() {
try {
System.out.println("Thread " + ++thread_count + " created, sleeping for 15 seconds.");
Thread.sleep(15 * 1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
---------- END SOURCE ----------
FREQUENCY : always
OS: Windows 10, Windows Server 2022.
OpenJDK: 11.0.22.0, 11.0.19, 11.0.18
A DESCRIPTION OF THE PROBLEM :
A sample Java program to create 500 threads and wait for them to end gracefully - would leak 2500+ event handles and few Thread handles consistently. 100% reproducible, sample code attached herewith.
The standalone sample code just demonstrates the handle leaks I see in on of our production code java services.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Note down a java programs handle count (using handle.exe / windbg.exe) before it creates multiple threads.
2. Wait for the threads to complete gracefully.
3. Note the handle count - I can see several windows Event object handles leaked.
Sample code attached below.
The program prints the PID and waits before creating 500 threads so user can run tools like sysinternals handle.exe or windbg to capture handle count, then user can press <Enter> to proceed with 500 threads creation, waits for graceful thread completion and pauses for user input during when user can run handle tool again to capture handle count / delta.
It will be evident 2500+ Event handles, and few Thread handles are leaked in this execution. I waited for hours/days - still handles are not released.
Code is attached to reproduce this issue.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No handle leaks.
ACTUAL -
PROGRAM OUTPUT:
Process ID: 11748
Note process handle count using tools - handle/windbg, press Enter to create 500 threads.
Starting 500 threads...
Thread 73 created, sleeping for 15 seconds.
Thread 151 created, sleeping for 15 seconds.
Thread 45 created, sleeping for 15 seconds.
Thread 150 created, sleeping for 15 seconds.
.....
Thread 453 created, sleeping for 15 seconds.
500 threads stopped, check handle count.
Press Enter to exit.
Process ID: 11748
Note process handle count using tools - handle/windbg, press Enter to create 500 threads.
HANDLE TOOLS OUTPUT:
(Mon 04/22/2024 11:02:23.97) X:\Tools\SysinternalsSuite>handle -s -p 11748
Handle v3.5
Copyright (C) 1997-2012 Mark Russinovich
Sysinternals - www.sysinternals.com
Handle type summary:
ALPC Port : 1
Desktop : 1
Directory : 2
EtwRegistration : 68
Event : 125
File : 13
IoCompletion : 3
IRTimer : 4
Key : 11
Mutant : 2
Section : 2
Semaphore : 34
Thread : 19
TpWorkerFactory : 2
WaitCompletionPacket: 6
WindowStation : 2
Total handles: 295
(Mon 04/22/2024 11:02:25.36) X:\Tools\SysinternalsSuite>handle -s -p 11748
Handle v3.5
Copyright (C) 1997-2012 Mark Russinovich
Sysinternals - www.sysinternals.com
Handle type summary:
ALPC Port : 1
Desktop : 1
Directory : 2
EtwRegistration : 68
Event : 2640
File : 13
IoCompletion : 3
IRTimer : 4
Key : 11
Mutant : 2
Section : 2
Semaphore : 34
Thread : 23
TpWorkerFactory : 2
WaitCompletionPacket: 6
WindowStation : 2
Total handles: 2814
---------- BEGIN SOURCE ----------
import java.util.ArrayList;
import java.util.Scanner;
public class Main implements Runnable {
public static void main(String[] args) {
System.out.println("Process ID: " + ProcessHandle.current().pid()) ;
System.out.println("Note process handle count using tools - handle/windbg, press Enter to create 500 threads.");
try (var inp = new Scanner(System.in)) {
inp.nextLine();
var task = new Main();
task.startThreads();
task.waitForThreadsToComplete();
System.out.println("Press Enter to exit.");
inp.nextLine();
}
}
ArrayList<Thread> thread_list = new ArrayList<Thread>();
static int thread_count = 0;
public void startThreads() {
System.out.println("Starting 500 threads...");
for (int i = 0; i < 500; ++i) {
Thread t = new Thread(this);
t.start();
thread_list.add(t);
}
System.out.println("500 threads started...");
}
public void waitForThreadsToComplete() {
System.out.println("Waiting for 500 threads to stop...");
thread_list.forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
System.out.println("500 threads stopped, check handle count.");
}
@Override
public void run() {
try {
System.out.println("Thread " + ++thread_count + " created, sleeping for 15 seconds.");
Thread.sleep(15 * 1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
---------- END SOURCE ----------
FREQUENCY : always
- links to
-
Review(master) openjdk/jdk/19778