Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Java guarantee that currently synchronized objects are not garbage collected?

Is there any guarantee that an object will not be garbage collected while a thread holds its monitor?

e.g.

class x {
    private WeakReference<Object> r;

    Object getMonitorObject() {
        Object o = new Object();
        r = new WeakReference<>(o);
        return o;
    }

    void thread1() throws Exception {
        synchronized (getMonitorObject()) {
            Thread.sleep(3000);
        }
    }

    void thread2() {
        Object b = r.get();
    }
}

In this case concretely, is there any guarantee that b will be non-null if thread2() is called while another thread is sleeping in thread1()? Let's just assume the whole of thread2() is executed while thread1() is sleeping in a different thread.

like image 382
Jesse Avatar asked Sep 10 '19 14:09

Jesse


People also ask

Can you guarantee the garbage collection process in Java?

No, Garbage collection does not guarantee that a program will not run out of memory. The purpose of garbage collection (GC) is to identify and discard objects that are no longer needed by a Java program, so that their resources can be reclaimed and reused.

How do I make sure an object is not garbage-collected?

We have three ways to achieve same - 1) Increasing the Heap -Eden space size . 2) Create Singleton class with Static reference . 3) Override finalize() method and never let that object dereference.

Do Java threads get garbage-collected?

No thread (or the things it refers to) will be garbage-collected while it is still running.

What will happen if there is no garbage collector in Java?

If you don't have enough memory to run your application, you will experience slowdowns, long garbage collection times, "stop the world" events, and eventually out of memory errors. This can indicate that your heap is too small, but can also mean that you have a memory leak in your application.


3 Answers

Synchronization can prevent the garbage collection, but not in general. In your specific case, it is not guaranteed.

Compare with JLS §12.6.1

Transformations of this sort may result in invocations of the finalize method occurring earlier than might be otherwise expected. In order to allow the user to prevent this, we enforce the notion that synchronization may keep the object alive. If an object's finalizer can result in synchronization on that object, then that object must be alive and considered reachable whenever a lock is held on it.

Note that this does not prevent synchronization elimination: synchronization only keeps an object alive if a finalizer might synchronize on it. Since the finalizer occurs in another thread, in many cases the synchronization could not be removed anyway.

So, since your object has no custom finalizer, no synchronization during finalization may happen and in principle, your object is a temporary object that allows lock elimination, in which case it would not prevent the garbage collection.

But there is the practical obstacle that you stored a WeakReference in a way that another thread could retrieve the object while it is not collected and once this possibility exist, the object is not local anymore and lock elimination can not be applied.

A theoretical implementation that aggressively collects the object immediately after construction (or eliminates its existence completely) and clears the weak reference before it escapes or creates an empty WeakReference in the first place, would be within the specification, as in that execution scenario, the lock elimination is justified.


Note that even if you insert a reachabilityFence, there is no happens-before relationship between a thread calling thread1() and another calling thread2(), so the second thread may always behave as-if executing thread2() after the other completed the synchronized block or passed the reachability fence, even if your real life clock tells otherwise. It’s said explicitly that Thread.sleep has no synchronization semantics.

like image 168
Holger Avatar answered Oct 23 '22 15:10

Holger


In order for the end of the synchronized block to remove the monitor lock, the synchronized block has to keep a reference to the object returned by getMonitorObject().

That reference prevents GC, so answer is yes.

like image 23
Andreas Avatar answered Oct 23 '22 15:10

Andreas


I've just come across an "aside" in the javadocs that says this:

"[The m]ethod reachabilityFence is not required in constructions that themselves ensure reachability. For example, because objects that are locked cannot, in general, be reclaimed, it would suffice if all accesses of the object, in all methods of class Resource (including finalize) were enclosed in synchronized (this) blocks."

This seems to say that objects that are locked cannot be garbage collected.

I'm not sure if that takes precedence over JLS 12.6.1 and 12.6.2; see my other answer, or if we should read this as only applying to Java (language) implementations for the Oracle / OpenJDK Java class libraries.

like image 2
Stephen C Avatar answered Oct 23 '22 13:10

Stephen C