Community
Participate
Working Groups
Created attachment 278743 [details] Test program showing the issue When using JDT's ASTParser standalone, opened ZipFile instances for resolving bindings from the classpath are never closed. This makes it impossible to touch the files on the classpath - until the ZipFile instances opened by JDT are destroyed by the garbage collector. The attached test program shows the problem. "test.jar" is a dummy JAR file that is added to the classpath of the ASTParser. Then "ASTParser.createASTs" is used to parse a Java source file. After it returns, attempting to delete "test.jar" fails on Windows platforms with: java.nio.file.FileSystemException: test.jar: The process cannot access the file because it is being used by another process. at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86) at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97) at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102) at sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:269) at sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103) at java.nio.file.Files.delete(Files.java:1126) at com.example.jdtzipleak.JdtZipLeak.main(JdtZipLeak.java:39) If "System.gc()" is un-commented, deleting the file succeeds. This is because the file handles are cleaned up automatically when they are destroyed. The suspected cause is that a new "NameEnvironmentWithProgress" is created in CompilationUnitResolver.resolve (see https://github.com/eclipse/eclipse.jdt.core/blob/3d670fe48cd3ec2fe4d3f7a2fca5830a4057291b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java#L649). However, `environment.cleanup()` is not called in the finally block. This means that the classpath is never cleaned up. Adding `environment.cleanup()` in the existing finally block of `CompilationUnitResolver.resolve` also avoids the issue.
I imagine the current design is driven by needs for working with bindings (I saw you have parser.setResolveBindings(true)): when you query any of the bindings in the result for additional details, it may be necessary to perform additional lookup of types. This needs the name environment to exist as long as those bindings are in use. The javadoc of setResolveBindings() mentions: "...The additional space is not reclaimed until the AST, all its nodes, and all its bindings become garbage. So it is very important to not retain any of these objects longer than absolutely necessary...." I could imagine addition of a method like AST#releaseNameEnvironment() Not sure if this has been discussed before. Perhaps this is a bad idea, but with this we could create a protocol that enables clients to tell us, when internal context can be freed. Technical note: AST seems to be the central location where we hold the BindingResolver. If it is a DefaultBindingResolver with a non-null #scope, then we will have a path towards the name environment (and the LookupEnvironment, too, while we're at it). PS: obviously, the actual symptom is a windows-only issue.
(In reply to Stephan Herrmann from comment #1) > I imagine the current design is driven by needs for working with bindings (I > saw you have parser.setResolveBindings(true)): when you query any of the > bindings in the result for additional details, it may be necessary to > perform additional lookup of types. This needs the name environment to exist > as long as those bindings are in use. At least for the batched API (ASTParser.createASTs) with FileASTRequestor I thought that this is only possible from inside FileASTRequestor, i.e. the objects are no longer usable after "createASTs" returns. For example, FileASTRequestor.createBindings only works from within the "createASTs" call. However, given that there are also separate "ASTParser.createAST" methods that directly return an AST node with the bindings, I'm guessing that this is not the case. > The javadoc of setResolveBindings() mentions: > "...The additional space is not reclaimed until the AST, all its nodes, and > all its bindings become garbage. So it is very important to not retain any > of these objects longer than absolutely necessary...." > > I could imagine addition of a method like > AST#releaseNameEnvironment() > > Not sure if this has been discussed before. Perhaps this is a bad idea, but > with this we could create a protocol that enables clients to tell us, when > internal context can be freed. I definitely think there should be some way to signal that processing has been completed, and that the remaining open system resources can be freed. > Technical note: AST seems to be the central location where we hold the > BindingResolver. If it is a DefaultBindingResolver with a non-null #scope, > then we will have a path towards the name environment (and the > LookupEnvironment, too, while we're at it). > > PS: obviously, the actual symptom is a windows-only issue. Technically yes, but having many open files is also bad for long running daemon processes. And I don't think we can rely on having the garbage collector clean it up reliably.
We are also affected by this bug when doing a SVN Team/Update and a JAR file was updated. We are using Subclipse. Our workaround is now to click on the "Run Garbage Collector" icon, then perform a Team/Refresh/Clean up and Team/Update again. This then updates the JAR file correctly.
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant. -- The automated Eclipse Genie.