Can the JVM GC move objects in the middle of a reference comparison, causing a comparison to fail even when both sides refer to the same object?

Java Bytecode instructions are always atomic in relation to the GC (i.e. no cycle can happen while a single instruction is being executed).

The only time the GC will run is between two Bytecode instructions.

Looking at the bytecode that javac generates for the if instruction in your code we can simply check to see if a GC would have any effect:

// a GC here wouldn't change anything
ALOAD 1
// a GC cycle here would update all references accordingly, even the one on the stack
ALOAD 2
// same here. A GC cycle will update all references to the object on the stack
IF_ACMPNE L3
// this is the comparison of the two references. no cycle can happen while this comparison
// "is running" so there won't be any problems with this either

Aditionally, even if the GC were able to run during the execution of a bytecode instruction, the references of the object would not change. It's still the same object before and after the cycle.

So, in short the answer to your question is no, it will always output true.


Source:

https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.21.3

The short answer is, looking at the java 8 specification: No.

The == operator will always perform object equality check (given that neither reference is null). Even if the object is moved, the object is still the same object.

If you see such an effect, you have just found a JVM bug. Go submit it.

It could, of course, be that some obscure implementation of the JVM does not enforce this for whatever strange performance reason. If that is the case, it would be wise to simply move on from that JVM...