7

Suppose we have a program like this:

void main() {
    // Point 0
    BigThing bt = new BigThing();
    // Point 1
    WeakReference<BigThing> weak = new WeakReference<>(bt);
    // Point 2
    doSomething(weak);
    // Point 3
}

void doSomething(...) { ... }

We know that the weak reference to the BigThing object cannot prevent the object from being garbage collected when it becomes no longer strongly reachable.

My question is about the local variable bt which is a strong reference to the BigThing object. Does the object become not-strongly-reachable at point 2 (just before calling doSomething()) or at point 3 (end of block scope)?

The answer to this question will affect whether the call to doSomething() is guaranteed to be able to access the live BigThing object, or whether the underlying object can die during the function call.

I am uncertain because you could argue that after point 2, the local variable bt is never read or written anymore, so the variable is effectively dead and the pointer value can be discarded. This "optimization" would be valid if all references were strong, but the reasoning falls apart when the notions of soft, weak, and phantom references are introduced, and finalizers as well. Also as an analogy, because C++ has destructors, a value must be destructed at the end of the scope, and cannot be moved ahead to the point of last usage.

Nayuki
  • 17,911
  • 6
  • 53
  • 80
  • 2
    In Java, “scope” is a compile-time artifact and does not affect the garbage collector at runtime in any way. – Holger Oct 07 '16 at 17:45
  • Same topic but for C#: https://devblogs.microsoft.com/oldnewthing/20100810-00/?p=13193 – Nayuki Nov 30 '21 at 02:02

2 Answers2

5

I would say the object is collectable at point 2, going by the following language in JLS section 12.6.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. For example, a Java compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner.

Since the bt variable will no longer be used after point 2, Java is free to clear that variable, rendering the BigThing object only weakly reachable.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • 1
    "I would say" is a bit overly humble, I think. This explicitly calls out exactly the OP's scenario. Good find! – yshavit Sep 02 '16 at 06:14
  • @user2357112 I understand your answer, but if we compile with the debug information, then doesn't it do the optimization, i mean if we debug this code flow put a break point after point 2, we should be able to evaluate the value referred by bt? – hunter Sep 02 '16 at 06:38
  • 1
    @hunter: I don't think the JLS makes any mention of debuggers, and I don't think it guarantees anything about what optimization effects you might see if you run your code under a debugger. What you'll see in a debugger is up to the implementation. – user2357112 Sep 02 '16 at 06:43
  • 1
    It’s worth noting that this is not a theoretical issue, see [“finalize() called on strongly reachable object in Java 8”](http://stackoverflow.com/q/26642153/2711488). Regarding debuggers, the mere existence of debug information is no reason to omit optimizations, after all, a JVM knows all existing breakpoints and will know when you try to set a new one and can still de-optimize *then*. – Holger Oct 07 '16 at 17:43
3

Java 9 introduces Reference.reachabilityFence to solve this case, which of course also implies that it does exist in the first place.

Nayuki
  • 17,911
  • 6
  • 53
  • 80
the8472
  • 40,999
  • 5
  • 70
  • 122
  • 1
    Ooh, nice! I've been wondering if there's a good way to delay finalization of an object, and it looks like a good way is coming. – user2357112 Sep 08 '16 at 23:41