It's well known that GCs will sometimes move objects around in memory. And it's to my understanding that as long as all references are updated when the object is moved (before any user code is called), this should be perfectly safe.
However, I saw someone mention that reference comparison could be unsafe due to the object being moved by the GC in the middle of a reference comparison such that the comparison could fail even when both references should be referring to the same object?
ie, is there any situation under which the following code would not print "true"?
Foo foo = new Foo(); Foo bar = foo; if(foo == bar) { System.out.println("true"); }
I tried googling this and the lack of reliable results leads me to believe that the person who stated this was wrong, but I did find an assortment of forum posts (like this one) that seemed to indicate that he was correct. But that thread also has people saying that it shouldn't be the case.
When Java programs run on the JVM, objects are created on the heap, which is a portion of memory dedicated to the program. Eventually, some objects will no longer be needed. The garbage collector finds these unused objects and deletes them to free up memory.
When the JVM doesn't have necessary memory space to run, the garbage collector will run and delete unnecessary objects to free up memory. Unnecessary objects are the objects which have no other references (address) pointing to them.
Common triggers for garbage collection are Eden space being full, not enough free space to allocate an object, external resources like System. gc(), tools like jmap or not enough free space to create an object.
As long as an object is being referenced, the JVM considers it alive. Once an object is no longer referenced and therefore is not reachable by the application code, the garbage collector removes it and reclaims the unused memory.
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...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With