Can the JVM GC move objects in the middle of a ref

2019-03-09 15:21发布

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.

8条回答
【Aperson】
2楼-- · 2019-03-09 15:36

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.

查看更多
该账号已被封号
3楼-- · 2019-03-09 15:36

No, because that would be flagrantly ridiculous and a patent bug.

The GC takes a great deal of care behind the scenes to avoid catastrophically breaking everything. In particular, it will only move objects when threads are paused at safepoints, which are specific places in the running code generated by the JVM for threads to be paused at. A thread at a safepoint is in a known state, where the positions of all the possible object references in registers and memory are known, so the GC can update them to point to the object's new address. Garbage collection won't break your comparison operations.

查看更多
The star\"
4楼-- · 2019-03-09 15:38

TL;DR

You should not think about that kind of stuff what so ever, It's a dark place. Java has clearly stated out it's specifications and you should not doubt it, ever.

2.7. Representation of Objects

The Java Virtual Machine does not mandate any particular internal structure for objects.

Source: JVMS SE8.

I doubt it! If you may doubt this very basic operator you may find yourself doubt everything else, getting frustrated and paranoid with trust issues is not the place you want to be.

What if it happens to me? Such a bug should not be existed. The Oracle discussion you supplied reporting a bug that happened years ago and somehow discussion OP decided to pop that up for no reason, either without reliable documentation of such bug existed now days. However, if such bug or any others has occurred to you, please submit it here.

To let your worries go away, Java has adjusted the pointer to pointer approach into the JVM pointer table, you can read more about it's efficenty here.

查看更多
Summer. ? 凉城
5楼-- · 2019-03-09 15:40

GCs only happen at points in the program where the state is well-defined and the JVM has exact knowledge where everything is in registers/the stack/on the heap so all references can be fixed up when an object gets moved.

I.e. they cannot occur between execution of arbitrary assembly instructions. Conceptually you can think of them occuring between bytecode instructions of the JVM with the GC adjusting all references that have been generated by previous instructions.

查看更多
放我归山
6楼-- · 2019-03-09 15:50

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...

查看更多
劳资没心,怎么记你
7楼-- · 2019-03-09 15:51

Java object hold a reference to the "object" not to the memory space where the object is stored.

Java do this because it allow the JVM to manage memory usage by its own (e.g. Garbage collector) and to improve global usage without impacting the client program directly.

As instance for improvement, the first X int (I don't remember how much) are always allocated in memory to execute for loop fatser (ex: for (int i =0; i<10; i++))

And as example for object reference, just try to create an and try to print it

int[] i = {1,2,3};
System.out.println(i);

You will see that Java returning a something starting with [I@. It is saying that is point on a "array of int at" and then the reference to the object. Not the memory zone!

查看更多
登录 后发表回答