github classgraph/classgraph classgraph-4.2.10

latest releases: classgraph-4.8.172, classgraph-4.8.171, classgraph-4.8.170...
5 years ago

Bugfix release -- remove the finalize() method from ScanResult, since finalizers are broken (#257).

This means you have to close ScanResult instances yourself in a try-with-resources block (or rely on the shutdown hook to close the ScanResult instance). This has always been the recommendation in the ClassGraph docs, but it is possible to forget to use ClassGraph in this way, especially in Scala, which does not have a try-with-resources construct. Recommendations for Java, Scala, Kotlin and Groovy are here:

https://github.com/classgraph/classgraph/wiki/API:-ScanResult#scanresult-lifecycle

Finalizers are fundamentally even more broken than I was aware of. The problem in this case is that a finalizer method can be run on an object while other methods of the same object are still executing -- i.e. the "this" reference of a method invocation is not considered in scope for liveness analysis (which feeds into reachability analysis), unless there is a possible future reference to a field of that object. This is "broken by design" in order to save a tiny performance margin in the Hotspot VM:

http://mail.openjdk.java.net/pipermail/hotspot-dev/2018-October/034625.html

It is possible to hold object references using a new Reference::reachabilityFence method in JDK 9+:

http://mail.openjdk.java.net/pipermail/jdk-dev/2018-October/002067.html

However this won't even solve all cases of this problem, for example (potentially) transitive dependencies, such as the back-ref to ScanResult in ClassInfo that allows the ClassInfo#loadClass() method to work:

new ClassGraph().enableClassInfo().scan().getAllClasses().loadClasses()

Also (source):

finalize() is broken for reasons beyond the "early" cleanup problem, and the "early" cleanup problem actually also applies equally to PhantomReference- and Cleaner-based solutions, as well as other *Reference types.

Reference::reachabilityFence is also not backwards compatible with JDK 7/8. I experimented with a JDK 7/8 emulation of this, but it seems like the only real "fix" is to remove the finalizer that called ScanResult#close(), and to simply rely on users closing ScanResult when they were finished with it.

This is reasonable, since users know that they should manually close (or assign in a try-with-resources block) anything that extends Closeable or Autocloseable (which ScanResult does).

If you don't close ScanResult when you are finished with it, your code may leak temporary files and/or file descriptors. These will be cleaned up by a shutdown hook (defined in ScanResult) on clean JVM shutdown, although killing the running code in Eclipse will fail to call shutdown hooks, so temporary files will remain on disk until reboot if you kill a running program that has not yet called ScanResult#close(). The best thing to do is to close the ScanResult as soon as you no longer need it.

Don't miss a new classgraph release

NewReleases is sending notifications on new releases.