Finalizer being run while class still in use (escape analysis bug)
Martin Buchholz
martinrb at google.com
Wed Oct 10 00:51:39 UTC 2018
Search for calls to Reference.reachabilityFence(this); in the jdk sources.
On Tue, Oct 9, 2018 at 5:35 PM, David Holmes <david.holmes at oracle.com>
wrote:
> Hi Luke,
>
> Moving this over to hotspot-dev. If it is an issue with the JIT escape
> analysis then hotspot-compiler-dev would be the place to raise this. But a
> general finalization issue may hit GC and runtime as well, so I redirected
> to the broader hotspot-dev.
>
> Also note that finalizers can run while methods of a class instance are
> still in progress [1]
>
> "Optimizing transformations of a program can be designed that reduce the
> number of objects that are reachable to be less than those which would
> naively be considered reachable."
>
> - this is one of the evil things about finalizers. So it may not be a
> bug, just surprising.
>
> Cheers,
> David
>
> [1] https://docs.oracle.com/javase/specs/jls/se11/html/jls-12.
> html#jls-12.6
>
>
> On 10/10/2018 10:27 AM, Luke Hutchison wrote:
>
>> A user of a library I maintain, ClassGraph, has reported that a finalizer
>> is being called on a class while methods of the class are still running,
>> indicating that the class, even though it overrides finalize(), is not
>> being correctly marked as GlobalEscape, so that escape analysis is trying
>> to garbage-collect the class too early. Is this mailing list the correct
>> place to report this bug?
>>
>> Here is the Maven rule for ClassGraph (you will also need to add Scala
>> deps) -- you will need version 4.2.8, since I put a mitigation in place in
>> version 4.2.9:
>>
>> <dependency>
>> <groupId>io.github.classgraph</groupId>
>> <artifactId>classgraph</artifactId>
>> <version>4.2.8</version>
>> </dependency>
>>
>> Here is the Scala code that reproduces the problem 100% of the time:
>>
>> import io.github.classgraph.{ClassGraph, ClassInfo}
>> import scala.collection.JavaConverters._
>> import scala.compat.Platform.ConcurrentModificationException
>>
>> while (true) {
>> try {
>> new ClassGraph().scan()
>> .getResourcesMatchingPattern(".*".r.pattern)
>> .asScala
>> .map(_.getURL)
>> } catch {
>> case cme: ConcurrentModificationException =>
>> cme.printStackTrace()
>> throw cme
>> }
>> }
>>
>> Then start the JVM with -XX:+DoEscapeAnalysis
>>
>> The code new ClassGraph().scan() returns a ScanResult, and then as soon as
>> ScanResult::getResourcesMatchingPattern is called with the ScanResult as
>> the invocation target, escape analysis sees that the ScanResult has "gone
>> out of scope" (despite the fact that the ScanResult is the invocation
>> target for a currently-running method), and immediately tries to garbage
>> collect it. This should not happen (1) since an invocation target should
>> never be marked for garbage collection while its methods are being run,
>> and
>> (2) since ScanResult overrides Object::finalize, so should have been
>> marked
>> as "GlobalEscape" by escape analysis.
>>
>> The finalizer for the ScanResult class calls ScanResult::close, which
>> clears the allResources list:
>>
>> https://github.com/classgraph/classgraph/blob/b9e8165d345753
>> 78697a727888457abb164311b8/src/main/java/io/github/
>> classgraph/ScanResult.java#L940
>>
>> This results in a ConcurrentModificationException since
>> ScanResult::getResourcesMatchingPattern is still iterating through
>> allResources:
>>
>> https://github.com/classgraph/classgraph/blob/b9e8165d345753
>> 78697a727888457abb164311b8/src/main/java/io/github/
>> classgraph/ScanResult.java#L383
>>
>> I read somewhere (and it makes sense) that escape analysis is performed by
>> the compiler, so maybe this is a Scala bug, but this behavior is triggered
>> by the JVM switch -XX:+DoEscapeAnalysis , and I couldn't find any
>> references to escape analysis information in the Java classfile format
>> spec, so that leads me to think this may be a JVM bug (which is why I am
>> asking on this list).
>>
>> Obviously having a garbage collector run a finalizer run while methods of
>> the object are still running is a very serious bug. Any pointers as to
>> where to report this issue would be appreciated. Thanks!
>>
>>
More information about the jdk-dev
mailing list