JDK-8202252 : (aio) Closed AsynchronousSocketChannel keeps completion handler alive
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 7,8,10,11
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: os_x
  • CPU: x86
  • Submitted: 2018-04-24
  • Updated: 2019-11-22
  • Resolved: 2018-07-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.
JDK 11 JDK 12 Other
11.0.5Fixed 12 b01Fixed openjdk8u232Fixed
Description
A DESCRIPTION OF THE PROBLEM :
When sun.nio.ch.UnixAsynchronousSocketChannelImpl is closed while a read() is pending, the field "readHandler" isn't set to null. This prevents a surrounding class from being garbage collected.



FREQUENCY : always



Comments
Andrei, please submit a separate testbug (RFE), if you want to include that test into codebase. I think it would make sense.
24-07-2019

Added another test for this bug (AsyncChannelLeak.java), which demonstrates the above scenario.
21-07-2019

In our case the symptoms are a bit different than in the bug description, but the same fix works fine. The problem is caused by the writeHandler holding a reference to a CompletionHandler long after the write operation completes. Since we had ~3000 async channels, and each CompletionHandler retained several MB of data, the application exhausted 10 GB heap rather quickly. Setting writeHandler=null in finishWrite() solves the issue.
16-07-2019

Fix Request (8u, 11u) Backporting this fix resolves the serious memory leak in aio. Patch applies cleanly to 11u, and requires usual reshufflings in 8u. New test fails without the product patch (has unusual failure mode: timeouts on failure, when tracked reference is not GC-ed) in both 8u and 11u, and passes with it. Additionally, tier1 passes in 11u and 8u.
16-07-2019

Users report this as the "severe memory leak in production" here: https://twitter.com/AndreiPangin/status/1151174582856011776 -- raising priority.
16-07-2019

Attached is the sample provided by submitter to demonstrate the issue. Included is a README.txt with a description of the problem, a workaround, and how to fix it.
03-05-2018

From submitter: AsynchronousSocketChannel chan = server.accept().get(); Session session = new Session(chan); Cleaner.register(session, chan::close); session.start(); /* chan.read() and after three seconds chan.close(); */ The session removes any reference to chan. But 'chan' is held by Cleaner, and the cleaning is never triggered, because 'chan.readHandler' holds a reference to the CompletionHandler which holds a reference to the session, so the session is never garbage collected.
30-04-2018

An example would be useful, I assume the user's code is keeping a reference to the AsynchronousSocketChannel object. There is nothing 10.0.1 specific here.
25-04-2018

To submitter: Can you please provide a test case which can demonstrate the memory leak that you have mentioned about in the bug report.
25-04-2018