-
Bug
-
Resolution: Fixed
-
P4
-
18
-
b15
-
generic
-
generic
-
Verified
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8343954 | 17.0.14 | Ben Taylor | P4 | Resolved | Fixed | b03 |
ADDITIONAL SYSTEM INFORMATION :
This issue appears to be in all versions of CompletableFuture
A DESCRIPTION OF THE PROBLEM :
CompletableFuture.orTimeout schedules a delayed task which is used to exceptionally complete the future with a TimeoutException if it has not otherwise completed before the timeout expires. If the future completes before the timeout the delayed task is canceled and removed from the delayed executors queue. The bug is that this only occurs if the future was completed non-exceptionally, when completed exceptionally the delayed task is not cancelled and its memory is thus retained until the timeout even though it will no longer serve any purpose. Given that timeouts should be significantly longer than expected completion times this leak could be non-negligible if exceptional completions occur frequently.
The issue is in CompletableFuture.Canceller.accept, which has the following check:
if (ex == null && f != null && !f.isDone())
f.cancel(false);
The "ex==null" appears to be a premature optimization and is the cause of the leak.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create timeout based CompletableFutures in a loop and complete them exceptionally.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Should run forever with periodic GC but no OOME.
---------- BEGIN SOURCE ----------
while (true) {
new CompletableFuture<>().orTimeout(1, TimeUnit.HOURS).completeExceptionally(new Exception());
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
don't use orTimeout :(
FREQUENCY : always
This issue appears to be in all versions of CompletableFuture
A DESCRIPTION OF THE PROBLEM :
CompletableFuture.orTimeout schedules a delayed task which is used to exceptionally complete the future with a TimeoutException if it has not otherwise completed before the timeout expires. If the future completes before the timeout the delayed task is canceled and removed from the delayed executors queue. The bug is that this only occurs if the future was completed non-exceptionally, when completed exceptionally the delayed task is not cancelled and its memory is thus retained until the timeout even though it will no longer serve any purpose. Given that timeouts should be significantly longer than expected completion times this leak could be non-negligible if exceptional completions occur frequently.
The issue is in CompletableFuture.Canceller.accept, which has the following check:
if (ex == null && f != null && !f.isDone())
f.cancel(false);
The "ex==null" appears to be a premature optimization and is the cause of the leak.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create timeout based CompletableFutures in a loop and complete them exceptionally.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Should run forever with periodic GC but no OOME.
---------- BEGIN SOURCE ----------
while (true) {
new CompletableFuture<>().orTimeout(1, TimeUnit.HOURS).completeExceptionally(new Exception());
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
don't use orTimeout :(
FREQUENCY : always
- backported by
-
JDK-8343954 CompletableFuture.orTimeout leaks if the future completes exceptionally
- Resolved
- relates to
-
JDK-8304557 java/util/concurrent/CompletableFuture/CompletableFutureOrTimeoutExceptionallyTest.java times out
- Closed
- links to
-
Commit openjdk/jdk/ded6a813
-
Commit(master) openjdk/jdk17u-dev/41b4812c
-
Review openjdk/jdk/13059
-
Review(master) openjdk/jdk17u-dev/3000
(1 links to)