Soft vs Weak References - java

I have a question on SoftReferences WeakReferences in Java.
What i know is:
GC uses algorithms to decide whether or not to reclaim a softly reachable object, but always reclaims a weakly reachable object.
Does that mean GC never runs the finalize() method on WeakReferences?
Thanks

As per The Truth About Garbage Collection
If a class defines a finalizer, then any instance of that class must
have the finalizer called prior to deallocation. This means that
deallocation is delayed by the inclusion of a finalizer.
Based on this my understanding is, irrespective of Week/Soft, if finalize defined, it will be called.

I don't follow your line of reasoning, but the finalizer is definitely always called. As soon as an object becomes finalizable, all soft/weak references to it will be cleared. So the refs can be observed as null before finalization.

Related

Java - Marked/Unmarked Objects in Concurrent Mark Sweep GC

I was going through this link from oracle and just trying to understand/confirm some points.
1) For CMS phases - If an object is marked as "Reachable" it also means that the object is live? Or "Live" and "Reachable" aren't "One and the Same" ?
2) If something is not marked as "Reachable" that is by default, Unreachable ? Or the simple principle "If I haven't marked you as Reachable, you are unreachable" ?
2) Even though it doesn't explicitly mention, I am assuming that after a certain threshold (may be some time stamp or some counter) is met, all old generation (NOT marked as "Reachable") objects are cleaned?
I must say that the link is quite nice but I guess I am one of those readers who looks for explicitly "Yes/No" statements. So if anyone can confirm with a simple yes/no to those questions above it will do :).
Thanks a lot.
If an object is not marked. It's "Unreachable"
"Unreachable" objects are not dead yet. It still lives in memory. But it's useless since no objects has reference to it. Dead in this context means "Kicked out of the old generation space".
With CMS GC, you have to set a old generation usage threshold with JVM option, It has it's default value. After memory usage reached threshold it starts to sweep out "Unreachable" objects (now it is released from memory)
The general formal definition of what is colloquially called “live”, “not garbage” or “dead”, “garbage” considers only reachability.
Compare with The Java® Language Specification, §12.6.1. Implementing Finalization:
Every object can be characterized by two attributes: it may be reachable, finalizer-reachable, or unreachable, and it may also be unfinalized, finalizable, or finalized.
A reachable object is any object that can be accessed in any potential continuing computation from any live thread.
A finalizer-reachable object can be reached from some finalizable object through some chain of references, but not from any live thread.
An unreachable object cannot be reached by either means.
An unfinalized object has never had its finalizer automatically invoked.
A finalized object has had its finalizer automatically invoked.
A finalizable object has never had its finalizer automatically invoked, but the Java Virtual Machine may eventually automatically invoke its finalizer.
So yes¹, reachable means “live” and unreachable means “dead” or “garbage” and yes¹, not being reachable implies being unreachable and marking the reachable objects is the most straight-forward way to test unreachability.
¹ just because you said you like the answer in terms of “yes” or “no”
The 3rd point can’t be answered with “yes” or “no”, as there is no such thing as “cleaning”.
unfinalized objects are referenced by a special list. If these objects are only reachable through this special reference, they get enqueued for finalization which turn them finalizable. These object are not unreachable yet.
Note that the JVM optimizes this step as the majority of all object doesn’t actually need finalization. If a class inherits the finalize() method from java.lang.Object or has an empty finalize() method, it is considered a “trivial finalizer” and instances of this class are not added to the list of unfinalized objects in the first place. This also applies to finalize() methods consisting of a sole super.finalize() call to another trivial finalizer.
So unreachable objects are objects whose finalizer has been executed already or having a “trivial finalizer”. In either case, no action is needed to “clean” them. These objects are not like garbage on the street that has to be picked up and put into the bin. The memory location still contains what it contained when the object was alive, but it’s unused. In fact, it was already unused before the garbage collector detected it.
The key point to end an objects life cycle is to make the memory available to new allocations. The sweeping of the CMS implies going through the memory and add the addresses of unreachable objects to a list of free memory. This phase starts directly after the marking, but as the C in CMS suggests, concurrently.
An alternative is compacting where other still reachable objects are moved to the location of unreachable objects. And copying will move (aka copy) all reachable objects to a new memory region, making the entire source region available to new allocations.
Common to all alternatives is that they are not doing anything with the garbage to “clean” it. Even when being part of the free memory, their memory will still contain whatever it had before, until being actually occupied and hence overwritten by another object.

Why is finalize() only called once by garbage collector?

Quotes from SCJP 6 study guide:
In the finalize() method you could write code that passes a reference
to the object in question back to another object, effectively uneligiblizing the object for garbage collection. If at some point later on this same object becomes eligible for garbage collection again, the garbage collector can still process this object and delete it. The garbage collector, however, will remember that, for this object, finalize() already ran, and it will not run finalize() again
Why is it designed so? The purpose of the finalize() method still holds good even when the object is marked of collection second time. Then why Java decides to skip call to finalize()?
I don't know if its the original reason, but the current implementation enqueues Finalizer instances (internal subclass of Reference) for objects overriding the finalize method with an internal ReferenceQueue that gets polled by a dedicated FinalizerThread.
And because the JVM has no way of knowing whether the object would need to be finalized a second time it cannot decide whether it would have to enqueue a new Finalizer once the finalize() method has been called.
Anyway, you should avoid using finalize(). It makes object allocation more costly, prevents escape analysis and is not a very reliable way of managing native resources because the GC can postpone the finalization for an unbounded amount of time.
Objects with an enabled finalizer are ineligible for collection; the GC only examines them after determining all the other objects which are ineligible for collection, however, and makes note of all the objects which would have been eligible for collection but for the existence of the enabled finalizer, and runs the finalize methods of such objects as soon as practical. Finalizable objects won't become eligible for collection until the finalizer has run, but the GC will have no way of distinguishing objects which become eligible for finalization as soon as the finalizer finishes, or those which were rendered ineligible for finalization as a result of actions by some object's finalizer and became eligible for collection at some later time.
The .NET Framework includes methods called IIRC GC.SuppressFinalize and GC.ReRegisterForFinalization which make it possible for code which knows an object's finalizer won't do anything useful to tell the GC not to bother calling it, and allows for code which knows a finalizer ran "too soon" to request that it run again later. The JVM, however, does not include such a feature. Since having all finalizable objects automatically reregistered for finalization once the finalizer runs would prevent them from ever getting collected, and since there's no way to manually reregister them, the net consequence is that there's no usable pattern via which an object's finalizer can be run more than once.
On the other hand, it is possible to achieve a similar effect by defining a nested class object which is finalizable, having the outer class object hold a reference to a nested-class instance, and having that nested class instance's "finalize" method chain back to cleanup code in its owner. If that cleanup code discards the nested-class instance and replaces it with a new one, then that new instance will trigger its finalizer (chaining back to its owner) on the next GC cycle where the owner is found to be unreferenced.

Importance of phantomreference in java

I wanted to understand the below statement in bold. What does it means? (Link)
An object which overrides finalize() must now be determined to be
garbage in at least two separate garbage collection cycles in order to
be collected. When the first cycle determines that it is garbage, it
becomes eligible for finalization. Because of the (slim, but
unfortunately real) possibility that the object was "resurrected"
during finalization, the garbage collector has to run again before the
object can actually be removed. And because finalization might not
have happened in a timely fashion, an arbitrary number of garbage
collection cycles might have happened while the object was waiting for
finalization. This can mean serious delays in actually cleaning up
garbage objects, and is why you can get OutOfMemoryErrors even when
most of the heap is garbage.
What phantomreference solves
With PhantomReference, this situation is impossible -- when a PhantomReference
is enqueued, there is absolutely no way to get a pointer to the now-dead object (which is good, because it isn't in memory any longer).
Because PhantomReference cannot be used to resurrect an object, the object can
be instantly cleaned up during the first garbage collection cycle in which it is found to be phantomly reachable.
Please help me understand the problem & the solution
Thanks
Contrary to popular belief, finalize methods are not triggered when their associated objects are garbage-collected, but rather when their associated objects would have been garbage-collected but for the existence of their non-default finalize methods. Objects cannot actually be garbage-collected until the system can be 100% certain that no reference to them will ever exist, but the act of running a finalize method creates a strong rooted reference to the object in question which will exist at least until the method exits. If during the execution of finalize a reference to the object gets stored elsewhere, that reference could continue to exist indefinitely. Consequently, no object whose finalized method is going to be called, nor any other object to which such an object holds a direct or indirect strong reference, can be collected until after the finalize method has run and the next GC cycle confirms that no reference to the object exists anymore.
The PhantomReference class serves to encapsulate a different paradigm: rather than keeping an object alive so the system can notify it that it's been abandoned and the only reason it's still alive is so it can receive notification of abandonment, objects requiring cleanup should create helper objects to process notification of their abandonment. If the helper objects avoid keeping references to any outside objects they don't "own", their existence won't interfere with the collection of their parent object, or other objects to which the parents hold direct or indirect references. The helper objects generally won't hold enough information to let them "do much", but that's good because they shouldn't have to do much. Instead, their design should be focused on performing the cleanup that will be required if their parent is abandoned.

overriding finalize(), referencing object inside it

What happens if I override finalize() and give reference to an object. Will that object ever be garbage collected? What is the other way to clean that object from the memory?
From the Javadoc:
The finalize method may take any action, including making this object available again to other threads.
However:
The finalize method is never invoked more than once by a Java virtual machine for any given object.
Finalize() is designed to be called by the garbage collector to remove de-referenced objects, if an object is re-referenced before Finalize() is called then you have simple prevented the GC from destroying it as it now has references again it is safe, that is assuming it was not taken during the period it was de-referenced, which could cause problems.
Remember that finalize is only called once by the JVM, so subsequence GCs will just run without giving another chance to reassign references, save objects, whatever. Potentially could cause a memory leak.

does Garbage collection process done in regular interval in java?

Garbage collection identify the objects that are no longer referred to by any variable and then reclaims the memory occupied by the objects.
I don't whether this process is done in a regular interval or as soon as an objects reference count falling down to zero.
suppose, if GC works immediately whenever an objects reference count falling down to zero then there is no need for requesting GC by calling System.GC();So, what is purpose of this method in this case?
GC is neither done in a regular interval nor as soon as an objects reference count falling down to zero (Note: that most JVM implementations do not use a reference counting algorithm, so this last point is moot).
When GC will run is decided by The garbage collection algorithm.
When you call System.gc(), you say to the garbage collector to make a clean-up. The problem is that it isn't clear when the GC will respond to your request. Even more, it is possible that GC to not run at all when you call it. In java you cannot predict how the GC will work. (That's why is considered bad practice to put your cleanup code in Object's finalize() method). In Java, the out of reference objects are collected for garbage automatically. That's why you don't need to call System.gc(). In special cases, when you want run it if possible, you can try to make use of this method, but the behavior is not guaranteed. (as specified above).
Most modern JVMs use a "stop-the-world" garbage collector, that is a garbage collector that stops all the application threads in the program, performs the garbage collection, and then resumes the application threads. This means that before doing the garbage collection, all threads in the application should reach a point that is safe to stop the thread.
An Object becomes eligible for Garbage collection or GC if its not reachable from any live threads or any static refrences in other words you can say that an object becomes eligible for garbage collection if its all references are null. Cyclic dependencies are not counted as reference so if Object A has reference of object B and object B has reference of Object A and they don't have any other live reference then both Objects A and B will be eligible for Garbage collection.
Generally an object becomes eligible for garbage collection in Java on following cases:
1) All references of that object explicitly set to null e.g. object = null
2) Object is created inside a block and reference goes out scope once control exit that block.
3) Parent object set to null, if an object holds reference of another object and when you set container object's reference null, child or contained object automatically becomes eligible for garbage collection.
4) If an object has only live references via WeakHashMap it will be eligible for garbage collection.
There are methods like System.gc () and Runtime.gc () which is used to send request of Garbage collection to JVM but it’s not guaranteed that garbage collection will happen.
There are two answers:
It is not specified by the JVM spec, the JLS or any of the other definitive Java documents when the garbage collector will run. It is therefore implementation specific.
In practice, a couple of different strategies are commonly used. For a non-concurrent collector, the GC is triggered when an attempted allocation fails because there isn't enough unallocated space. For a concurrent collector, a collection is started when the amount of free space falls below a pre-determined threshold. (For HotSpot concurrent GC's, the threshold ratio is a tunable parameter.)
No modern Java GC uses reference counts.
The purpose of the System.gc() is to allow an application to give the JVM a hint that "now would be a good time to run the garbage collector". The JVM is allowed to ignore that hint. As a general rule, triggering the GC that way is inefficient in terms of CPU usage. The only legitimate reason to do it in production code is as a way to avoid GC pauses in a highly interactive application. (You try to force a GC at a point when you know that interactivity is not required; e.g. between "levels" in a game.)

Categories

Resources