-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8212136: Remove finalizer implementation in SSLSocketImpl #8065
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
👋 Welcome back xuelei! A progress list of the required criteria for merging this PR into |
@XueleiFan The following label will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command. |
Webrevs
|
ping ... |
Need an update, close the review for now. |
The socket close() call in the finalize() method may be blocked for the SSL implementation, which is not good for garbage collection. It should be safe by just removing the finalize() method. |
Can you provide more detail on why simply removing the |
The 1st use of Cleaner refer to 'this' object, as result in that 'this' object cannot be phantom reachable and thus the cleaner cannot be triggered. As the close() is a method of 'this' object, the calling to close() in a cleaner will hold a reference to 'this' object, and make the cleaner failed (and memory leak). |
Thanks for the explanation: this is my first exposure to the I see now what was being talked about in your other PR: #8136 and to not use a reference to That said, we still need to send the close_notify at the TLS layer, right? Simply removing the finalize() method is just going to silently shutdown the connection, and then the Socket is going to do whatever it does for finalization/Cleaning. |
The Socket implementation will take care of the file description/native memory release, I think.
It is expected to send the close_notify at the TLS layer. But the current code using finalizer, which is not reliable. The underlying socket may have been closed when the SSLSocket finalizing action is triggered. Generally, application should call close() method explicitly, otherwise the finalizer is not expect to work reliable. I was wondering it may be safe to remove the finalizer. I agree that adding a best effort cleanup may be better. I was wondering to check if it is possible to clean the socket in the socket creation factories so that the object reference issues could be resolved. But as socket is a kind of resource, application layer may make the clean up as well.
I'm still looking for a solution to clean up resource by using a method of 'this'. Please advice if anyone has experiences. |
I've walked through the network code and understand it now. The Socket creation code calls into sun.nio.ch.NioSocketImpl.create():451, which then allocates the FileDescriptor fd and assigns it to the Socket, then registers a closer for that FileDescriptor which will be triggered by the Socket GC. When the Socket is reclaimed, the FileDescriptor is released, but not by referencing the Socket itself.
Yeah, I'm just not sure yet.
@AlanBateman, @dfuch, @bchristi-git, any great ideas here? |
As you have found, if an open Socket is unreferenced then a cleaner can close the underlying socket (and release the file descriptor). The Cleaner is setup by the SocketImpl implementation. What is the existing behavior with the BaseSSLSocketImpl finalizer? Does it just close the socket or does it to the close_notify before closing the socket. If it does, and you want to keep that behavior, then you are probably into significant refactoring to avoid a reference to the BaseSSLSocketImpl. |
The existing behavior is trying to close the socket and send the close_notify. As the socket closure has been done in the SocketImpl, I think BaseSSLSocketImpl could rely on to the SocketImpl cleaner. So the left for the cleaning is about the close_notify. |
@AlanBateman, just to clarify, send the close_notify first, then close the socket. From the Socket's point of view, the encrypted close_notify message is just a few bytes of application data sent over the Socket's OutputStream. |
I parsed the finalize() code one more time. The sending close_notify may be not an expected part of the finalize() implementation. The finalize() calls the close() method. If the socket is layered over a preexisting socket, the preexisting socket is closed by calling it close() method: See the BaseSSLSocketImpl.close() method:
For layered over socket case, if the preexisting socket is not an SSLSocket object(which is the common case), no close_notify will be sent off course. If the preexisting socket is an SSLSocket object (which may be not common), the SSLSocketImpl.close() will be called and the close_notify could be sent. For non-layered over sockets, as super.close() is called, there is no close_notify delivered during the finalizing. Based on the cases above, the close_notify delivery may be not an expected behavior during finalization in practice. I would like to remove the finalize() method without adding a cleaner, as shown in the current PR. But if you read the code and behavior differently , it's acceptable to me to clean up the preexisting socket, by adding a cleaner like:
Please let me know your preference. |
IMO we should not send close_notify in the finalizer. It's the application's responsibility to send close_notify when it's done with the socket; we should not pretend that it was closed normally when it was not. |
ping ... |
@djelinski makes an excellent point which I hadn't really considered. This is an error situation. As the native Socket resources are cleaned/released as needed, a simple removal might actually be appropriate. @XueleiFan I'm going to send you some internal discussion we've had in a minute. Let's both parse it and see if there is anything further we should consider, and circle back tomorrow and finalize the plan & push. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, after much back and forth, I'm convinced this is ok.
@dfuch commented in another thread:
An application should really close its sockets and not let them get garbage collected without closing them: this is sloppy.
So brutally closing the underlying TCP connection in that case should be an acceptable behaviour, and that would be achieved by just removing the finalize.
Thanks for allowing me to look more deeply into this.
@XueleiFan, would you please add a note to the bug itself with the end-result, and a quick note in the place of the finalizer a quick summary of what we decided.
@XueleiFan This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 413 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
@@ -262,37 +262,6 @@ public boolean isOutputShutdown() { | |||
} | |||
} | |||
|
|||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please add a quick couple lines here with the technical rationale for removing it, so we don't forget down the road.
i.e.
There used to be a finalize() here, but decided that was not
needed. If users don't properly close the socket...
The native resources are handled by the Socket Cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be not common to comment on non-existing method. Maybe, the class description could be a place to add this note.
Sure. Notes were added in JBS and the patch. |
@@ -41,6 +41,11 @@ | |||
* Methods are defined final to ensure that they are not accidentally | |||
* overridden in SSLSocketImpl. | |||
* | |||
* There used to be a finalize() implementation, but decided that was |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you haven't pushed yet, maybe:
There used to be a finalize() implementation that sent close_notify's, but decided that was not needed. Not closing properly is more properly an error condition that should be avoided. Applications should close sockets and not rely on garbage collection.
The underlying native resources are handled by the Socket Cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the rewording. Updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the rewording. Updated.
I made one more tweak that reads better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it looks better. Updated. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, thanks.
Given that this proposed change will change the behavior for SSLSocket (& SSLServerSocket?) I would also suggest to file a CSR before integrating. |
/csr |
@XueleiFan an approved CSR request is already required for this pull request. |
CSR and release note requests are filed in JBS. May I have them reviewed? CSR: https://bugs.openjdk.java.net/browse/JDK-8286064 |
/csr needed |
Could someone in Oracle help to run the Mach5 testing for security and network components (or just tier1 and tier2), and let me know if this update causes any failures? |
Builds underway. |
tier1/tier2 passed. |
linux-x64 Infra + JCK passed. Looks good. |
Even though this doesn't appear to be a big change, I would advise not integrating until next week as the Loom integration into 19 is planned for this weekend and it would be better to have as few disruptions as possible. Thanks! |
/integrate |
Going to push as commit 034f20f.
Your commit was automatically rebased without conflicts. |
@XueleiFan Pushed as commit 034f20f. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
Please review the update to remove finalizer method in the SunJSSE provider implementation. It is one of the efforts to clean up the use of finalizer method in JDK.
Progress
Issues
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/8065/head:pull/8065
$ git checkout pull/8065
Update a local copy of the PR:
$ git checkout pull/8065
$ git pull https://git.openjdk.java.net/jdk pull/8065/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 8065
View PR using the GUI difftool:
$ git pr show -t 8065
Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/8065.diff