How does Java solve retain cycles in garbage collection? - java

I know that a retain cycle (at least in Objective-C and Swift) is when two objects claim ownership of one another (they have references to each other). And in Objective-C we can solve the issue by declaring one of them weak.
From what I have read and understood, the Java GC is not affected by retain cycles, and we do not have to worry about weak references. How does it solve it?

The Java (JVM) garbage collector works by looking for "reachable" objects - from the root(s) of the object tree. If they can't be reached (if they have no outside object references) then entire object graphs can be discarded.
Essentially it just just traverses the tree from root(s) to leaf nodes and marks all objects it encounters. Any memory not taken up by marked objects in the heap is swept (marked as free). This is called mark and sweep. img src
This can't be done easily in objective-c because it uses reference counting, not mark and sweep which has it's flaws
The reason there can be no retain cycles is because if they aren't linked to the "tree" anywhere, they aren't marked and can be discarded.

The garbage collector looks for reachable objects, starting from the roots (typically: variables on the call stack or global variables). So if two objects reference each other but are not otherwise reachable they won't be flagged as "live" and will be collected.

As the name suggests, Garbage Collection refers to removing of objects
which are no longer in use. It is a well known fact that irrespective
of their scope objects, Java stores objects in heap. Thus, if we keep
on creating objects without clearing the heap, our computers might run
out of heap space and we get ‘Out of Memory’ error. Garbage Collection
in Java is a mechanism which is controlled and executed by the Java
Virtual Machine (JVM) to release the heap space occupied by the
objects which are no more in use. In contrast to C++, garbage
collection in java relives the developer from the Memory Management
related activities. The JVM executes this process with the help of a
demon thread called the ‘Garbage Collector’. The garbage collector
thread first invokes the finalize method of the object. This performs
the cleanup activity on the said object. As a developer we cannot
force the JVM to run the garbage collector thread. Though there are
methods e.g Runtime.gc () or System.gc(), but none of these assures
the execution of garbage collector thread. These methods are used to
send garbage collection requests to the JVM. It is up to the Java
Virtual machine when it will initiate the garbage collection process.
Take a look at this stuff
How Garbage Collection works in Java

In basic terms, Garbage Collection works by walking the object graphs from a number of predefined roots. Anything not accessible from those roots is garbage, therefore one object referencing another is irrelevant unless either can be accessed from one or more roots.
It's all explained in more detail in How Garbage Collection Really Works.

The behavior of a tracing garbage collector may be viewed as analogous to that of a bowling alley pinsetter, which automatically sweeps up all pins that have been knocked over without disrupting pins that are still standing. Rather than trying to identify knocked-over pins, the pinsetter grabs all of the pins that are still standing, lifts them off the alley, and then runs a sweeper bar over the alley surface, removing wholesale any pins that might happen to be there without knowing or caring where they are.
A tracing GC works by visiting a certain set of "rooted" object references (which are regarded as always "reachable") and objects that are reachable via references held in reachable objects. The GC will mark such objects and protect their contents somehow. Once all such objects have been visited, the system will then visit some "special" objects (e.g. lists of weak or phantom references, or references to objects with finalizers) and others which are reachable from them but weren't reachable from ordinary rooted references, and then regard any storage which hasn't been guarded as eligible for reuse.
The system will need to specially treat objects that were reachable from special objects but weren't reachable from ordinary ones, but otherwise won't need to care about "ordinary" objects that become eligible for collection. If an object doesn't have a finalizer and isn't targeted by a weak or phantom reference, the GC may reuse its associated storage without ever bothering to look at any of it. There's no need for the GC to worry about the possibility that a group of objects that aren't reachable via any rooted references might hold references to each other because the GC wouldn't bother examining of those references even if they existed.

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.

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

java - How can Garbage Collector quickly know which objects do not have references to them any more?

I understand that in Java, if an object doesn't have any references to it any more, the garbage collector will reclaim it back some time later.
But how does the garbage collector know that an object has or has not references associated to it?
Is garbage collector using some kind of hashmap or table?
Edit:
Please note that I am not asking how generally gc works. really, I am not asking that.
I am asking specifically that How gc knows which objects are live and which are dead, with efficiencies.
That's why I say in my question that is gc maintain some kind of hashmap or set, and consistently update the number of references an object has?
A typical modern JVM uses several different types of garbage collectors.
One type that's often used for objects that have been around for a while is called Mark-and-Sweep. It basically involves starting from known "live" objects (the so-called garbage collection roots), following all chains of object references, and marking every reachable object as "live".
Once this is done, the sweep stage can reclaim those objects that haven't been marked as "live".
For this process to work, the JVM has to know the location in memory of every object reference. This is a necessary condition for a garbage collector to be precise (which Java's is).
Java has a variety of different garbage collection strategies, but they all basically work by keeping track which objects are reachable from known active objects.
A great summary can be found in the article How Garbage Collection works in Java but for the real low-down, you should look at Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine
An object is considered garbage when it can no longer be reached from any pointer in the running program. The most straightforward garbage collection algorithms simply iterate over every reachable object. Any objects left over are then considered garbage. The time this approach takes is proportional to the number of live objects, which is prohibitive for large applications maintaining lots of live data.
Beginning with the J2SE Platform version 1.2, the virtual machine incorporated a number of different garbage collection algorithms that are combined using generational collection. While naive garbage collection examines every live object in the heap, generational collection exploits several empirically observed properties of most applications to avoid extra work.
The most important of these observed properties is infant mortality. ...
I.e. many objects like iterators only live for a very short time, so younger objects are more likely to be eligible for garbage collection than much older objects.
For more up to date tuning guides, take a look at:
Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning
Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide (Java SE 8)
Incidentally, be careful of trying to second guess your garbage collection strategy, I've known many a programs performance for be trashed by over zealous use of System.gc() or inappropriate -XX options.
GC will know that object can be removed as quickly as it is possible. You are not expected to manage this process.
But you can ask GC very politely to run using System.gc(). It is just a tip to the system. GC does not have to run at that moment, it does not have to remove your specific object etc. Because GC is the BIG boss and we (Java programmers) are just its slaves... :(
The truth is that the garbage collector does not, in general, quickly know which objects no longer have any incoming references. And, in fact, an object can be garbage even when there are incoming references it.
The garbage collector uses a traversal of the object graph to find the objects that are reachable. Objects that are not reached in this traversal are deemed garbage, even if they are part of a cycle of references. The delay between an object being unreachable, and the garbage collector actually collecting the object, could be arbitrarily long.
There is no efficient way - it will still require traversal of the heap, but there is a hacky way: when the heap is divided into smaller pieces (thus no need to scan the entire heap). This is the reason we have generational garbage collectors, so that the scanning takes less time.
This is relatively "easy" to answer when your entire application is stopped and you can analyze the graph of objects. It all starts from GC roots (I'll let you find the documentation for what these are), but basically these are "roots" that are not collected by the GC.
From here a certain scan starts that analyzes the "live" objects: objects that have a direct (or transitive) connection to these roots, thus not reclaimable. In graph theory this is know to "color/traverse" your graph by using 3 colors: black, grey and white. White means it is not connected to the roots, grey means it's sub-graph is not yet traversed, black means traversed and connected to the roots. So basically to know what exactly is dead/alive right now - you simply need to take all your heap that is white initially and color it to black. Everything that is white is garbage. It is interesting that "garbage" is really identified by a GC by knowing what is actually alive. There are some drawings to visualize this here for example.
But this is the simple scenario: when your application is entirely stopped (for seconds at times) and you can scan the heap. This is called a STW - stop the world event and people hate these usually. This is what parallel collectors do: stop everything, do whatever GC has to (including finding garbage), let the application threads start after that.
What happens when you app is running and you are scanning the heap? Concurrently? G1/CMS do this. Think about it: how can you reason about a leaf from a graph being alive or not when your app can change that leaf via a different thread.
Shenandoah for example, solves this by "intercepting" changes over the graph. While running concurrently with your application, it will catch all the changes and insert these to some thread local special queues, called SATB Queues (snapshot at the begging queues); instead of altering the heap directly. When that is finished, a very short STW event will occur and these queues will be drained. Still under the STW what that drain has "caused" is computed, i.e. : extra coloring of the graph. This is far simplified, just FYI. G1 and CMS do it differently AFAIK.
So in theory, the process is not really that complicated, but implementing it concurrently is the most challenging part.

Java "dead" objects not being garbage collected

I know that during garbage collection in Java, objects that don't have any more references to them are marked as "dead" so that they can be deleted from memory by the garbage collector.
My question is if, during a garbage collection phase, all of the "dead" objects get deleted from memory or some of them survive? Why would a "dead" object survive a garbage collection phase?
LATER EDIT
Thank you for all of your answers. I can deduce that the main reason why "dead" objects would not be deleted is due to timing or spacing limitations of the way the Garbage Collector operates.
However, supposing that the Garbage Collector can reach all of the "dead" objects, I was wondering if there is a way to declare, reference, use, dereference, etc.. an object such that somehow it would skip the deletion phase even though it is "dead". I was thinking maybe objects belonging to classes which have static methods or inner classes or something like that may be kept in memory for some reason, even though they have no references to them.
Is such a scenario possible?
Thank you
My question is if, during a garbage collection phase, all of the "dead" objects get deleted from memory or some of them survive? Why would a "dead" object survive a garbage collection phase?
All current HotSpot GCs are generational collectors. Quoting from Wikipedia:
"It has been empirically observed that in many programs, the most recently created objects are also those most likely to become unreachable quickly (known as infant mortality or the generational hypothesis). A generational GC (also known as ephemeral GC) divides objects into generations and, on most cycles, will place only the objects of a subset of generations into the initial white (condemned) set. Furthermore, the runtime system maintains knowledge of when references cross generations by observing the creation and overwriting of references. When the garbage collector runs, it may be able to use this knowledge to prove that some objects in the initial white set are unreachable without having to traverse the entire reference tree. If the generational hypothesis holds, this results in much faster collection cycles while still reclaiming most unreachable objects."
What this means for your question is that most GC cycles collect only garbage objects in young generations. A garbage object in the oldest generation can survive multiple GC cycles ... until the old generation is finally collected. (And in the new G1 GC, apparently the old generation is collected a bit at a time ... which can delay reclamation even further.)
Other causes for (notionally) unreachable objects to survive include:
Unreachable objects with (unexecuted) finalizers are attached to a finalization queue by the garbage collector for processing after the GC has finished.
Objects that are softly, weakly or phantom referenced are actually still reachable, and are handled by their respective reference queue managers after the GC has finished.
Objects that are reachable by virtue of JNI global references, etcetera. (thanks #bestss)
Various hidden references exist that relate instances, their classes and their classloaders.
There is a hidden reference from an inner instance to its outer instance.
There is a hidden reference from a class to the intern'd String objects that represent its string literals.
However, these are all consequences of the definition of reachability:
"A reachable object is any object that can be accessed in any potential continuing computation from any live thread." - JLS 12.6.1
It is also worth noting that the rules for the GC have an element of conservativeness about them. They say that a reachable object won't be deleted, but they don't say that an object that is (strictly) unreachable will be deleted. This allows for cases where an object cannot be accessed but the runtime system is unable to figure that out.
Your followup question:
However, supposing that the Garbage Collector can reach all of the "dead" objects, I was wondering if there is a way to declare, reference, use, dereference, etc.. an object such that somehow it would skip the deletion phase even though it is "dead".
"Dead" is not a well-defined term. If the garbage collector can reach the objects, they are by definition reachable. They will not be deleted while they are still reachable.
If they are both dead AND reachable (whatever "dead" means!) then the fact that they are reachable means they won't be deleted.
What you are proposing doesn't make sense.
I was thinking maybe objects belonging to classes which have static methods or inner classes or something like that may be kept in memory for some reason, even though they have no references to them. Is such a scenario possible?
Static methods don't have references ... unless they happen to be on the call stack. Then the local variables may contain references just like any other method call. Normal reachability rules apply.
Static fields are GC roots, for as long as the class itself exists. Normal reachability rules apply.
Instances of inner classes are no different to instance of other classes from a GC perspective. There can be a reference to an outer class instance in an inner class instance, but that leads to normal reachability.
In summary, there are some unexpected "causes" for reachability, but they are all a logical consequence of the definition of reachability.
As the System.gc() javadoc says
When control returns from the method
call, the Java Virtual Machine has
made a best effort to reclaim space
from all discarded objects.
From which you can infer that a call to the garbage collector does not insure that all unused object will be reclaimed. As the garbage collection can completely differ between implementation, no definitive answer can be given. There is even java implementations without any garbage collection.
One potential explanation for an unreachable object not being collected is time. As of Java 1.5 the amount of time the JVM spends garbage collecting can be limited using on of the following options...
-XX:MaxGCPauseMillis
-XX:GCTimeRatio=<nnn>
Both options are explained in detail here
There are dead objects in "young" generation and there are dead objects in "old" generation. If GC being performed in "minor GC", only dead objects from young generation will be collected.
Additionally, you can use finalize() method to stop VM from collecting your object by throwing exception from finalize() (at least, this is how I understand Object.finalize() javadoc: Any exception thrown by the finalize method causes the finalization of this object to be halted, but is otherwise ignored).
The behaviour of the garbage collector is not fully specified. If a particular implementation choose not to collect certain objects, it is allowed to do so. This could be done to avoid spending large periods of time in the garbage collector, which could have detrimental effects to the operation of the application.
Imagine you had a collection which contained millions of small objects, most of which were not referenced anywhere else. If the only references to that collection was cleared, would you want the GC to spend a long time cleaning out those millions of small objects, or would you want it to do so over the course of several calls? In most cases, the latter would be better for the application.

can any unused object escape from Garbage Collector?

Is there any possibility that a object which is not referenced anywhere and still existing on heap. I mean is there a possibility that a unused object getting escaped from garbage collector and be there on the heap until the end of the application.
Wanted to know because if it is there, then while coding i can be more cautious.
If an object is no longer referenced, it does still exist on the heap, but it is also free to be garbage-collected (unless we are talking Class objects, which live in PermGen space and never get garbage-collected - but this is generally not something you need to worry about).
There is no guarantee on how soon that will be, but your application will not run out of memory before memory from those objects is reclaimed.
However, garbage collection does involve overhead, so if you are creating more objects than you need to and can easily create less, then by all means do so.
Edit: in response to your comment, if an object is truly not referenced by anything, it will be reclaimed during garbage collection (assuming you are using the latest JVM from Sun; I can't speak toward other implementations). The reason why is as follows: all objects are allocated contiguously on the heap. When GC is to happen, the JVM follows all references to "mark" objects that it knows are reachable - these objects are then moved into another, clean area. The old area is then considered to be free memory. Anything that cannot be found via a reference cannot be moved. The point is that the GC does not need to "find" the unreferenced objects. If anything, I would be more worried about objects that are still referenced when they are not intended to be, which will cause memory leaks.
You should know that, before a JVM throws an out-of-memory exception, it will have garbage collected everything possible.
If an instance is no longer referenced, it is a possible candidate for garbage collection. This means, that sooner or later it can be removed but there are no guaranties. If you do not run out of of memory, the garbage collector might not even run, thus the instance my be there until the program ends.
The CG system is very good at finding not referenced objects. There is a tiny, tiny chance that you end up keeping a weird mix of references where the garbage collector can not decide for sure if the object is no longer referenced or not. But this would be a bug in the CG system and nothing you should worry about while coding.
It depends on when and how often the object is used. If you allocate something then deallocate (i.e., remove all references to it) it immediately after, it will stay in "new" part of the heap and will probably be knocked out on the next garbage collection run.
If you allocate an object at the beginning of your program and keep it around for a while (if it survives through several garbage collections), it will get promoted to "old" status. Objects in that part of the heap are less likely to be collected later.
If you want to know all the nitty-gitty details, check out some of Sun's gc documentation.
Yes; imagine something like this:
Foo foo = new Foo();
// do some work here
while(1) {};
foo.someOp(); // if this is the only reference to foo,
// it's theoreticaly impossible to reach here, so it
// should be GC-ed, but all GC systems I know of will
// not Gc it
I am using definition of: garbage = object that can never be reached in any execution of the code.
Garbage collection intentionally makes few guarantees about WHEN the objects are collected. If memory never gets too tight, it's entirely possible that an unreferenced object won't be collected by the time the program ends.
The garbage collector will eventually reclaim all unreachable objects. Note the "eventually": this may take some time. You can somewhat force the issue with System.gc() but this is rarely a good idea (if used without discretion, then performance may decrease).
What can happen is that an object is "unused" (as in: the application will not use it anymore) while still being "reachable" (the GC can find a path of references from one of its roots -- static fields, local variables -- to the object). If you are not too messy with your objects and structures then you will not encounter such situations. A rule of thumb would be: if the application seems to take too much RAM, run a profiler on it; if thousands of instances of the same class have accumulated without any apparent reason, then there may be some fishy code somewhere. Correction often involves explicitly setting a field to null to avoid referencing an object for too long.
This is theoretically possible (there is no guarantee the GC will always find all objects), but should not worry you for any real application - it usually does not happen and certainly does not affect a significant chunk of memory.
In theory, the garbage collector will find all unused objects. There could, of course, be bugs in the garbage collector…
That said, "In theory there is no difference between theory and practice, in practice, there is." Under some, mostly older, garbage collectors, if an object definition manages to reach the permanent generation, then it will no longer be garbage collected under any circumstances. This only applied to Class definitions that were loaded, not to regular objects that were granted tenured status.
Correspondingly, if you have a static reference to an object, that takes up space in the "regular" object heap, this could conceivably cause problems, since you only need to hold a reference to the class definition from your class definition, and that static data cannot be garbage collected, even if you don't actually refer to any instances of the class itself.
In practice though, this is a very unlikely event, and you shouldn't need to worry about it. If you are super concerned about performance, then creating lots of "long-lived" objects, that is, those that escape "escape-analysis", will create extra work for the garbage collector. For 99.99% of coders this is a total non-issue though.
My advice - Don't worry about it.
Reason - It is possible for a non-referenced object to stay on the heap for some time, but it is very unlikely to adversely affect you because it is guaranteed to be reclaimed before you get an out of memory error.
In general, all objects to which there are no live hard references, will be garbage-collected. This is what you should assume and code for. However, the exact moment this happens is not predictable.
Just for completeness, two tricky situations [which you are unlikely to run into] come into my mind:
Bugs in JVM or garbage collector code
So called invisible references - they rarely matter but I did have to take them into account one or two times during the last 5 years in a performance-sensitive application I work on

Categories

Resources