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.
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.
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.
No thread (or the things it refers to) will be garbage-collected while it is still running.
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.
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.
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.
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.
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