Currently I am learning about GC in Java, but I need some clarification. Let's say we have situation like on this picture:
According to this website first runs DefNew and after that Tenured GC. In that case:
In DefNew Object A has reference from Old generation, this won't be collected.
In Tenured (if I get it right), Object B won't be deleted because has a reference from Young Generation (Object A).
How does it works after all? I was thinking about dirty cards, but only Object C would be marked, because it was changed (deleted reference to Object B).
From an article about "nepotism" problem
This is 'pathological' because ANY promoted node will result in the promotion of ALL following nodes until a GC resolves the issue.
So I guess it will be promoted to Old gen first, then collected.
Related
I have Order_Item class instance, and these are paths to GC Roots (excluding phantom/weak/soft references):
I have few questions:
1) I'm not sure if the Order_Item will be garbage collected.
I tried to run System.gc(), and the object remained in heap.
Is it allowed to be collected, according to provided image?
2) What "Native Stack" mean?
As far as I understood, it's accounted as GC root.
http://help.eclipse.org/mars/index.jsp?topic=%2Forg.eclipse.mat.ui.help%2Fconcepts%2Fgcroots.html
Why some object (i.e. Order 0x782032cf8) is kept in "Native Stack"?
3) If I have reference from GC Root to object A, that object will not be garbage collected? Right?
And if so, my Order_Item object can't be garbage collected?
4) If 3 is right, how may I find what keeps objects 0x7821da5e0 and 0x782032cf8, and how to dereference/remove them?
You cannot really force the garbage collector to delete a given object. You know that the object is kept alive as long as it is reachable by references from the given point in the program. But if the object gets "collectable", it might be collected soon, but if there is no pressure on memory, it may fool around for a long time.
Usually, there is not reason to really delete objects if there is enough memory. The only exception I know are passwords. Here, you use a char array and overwrite it with nonsense once you used it.
For the native stack: Your link indicates that the native stack keeps external resources, e.g. files.
Could anyone please tell me what will be with objects that refer to each other? How does java's GC resolve that issue? Thanks in advance!
If you have object A and B, and if the following conditions hold:
A references to B
B references to A
No other objects reference to any one of them
They are not root objects (e.g. objects in the constants pool etc)
then, these two objects will be garbage collected. This is called "circular reference".
This is because the mark-and-sweep GC will scan and find out all the objects that are reachable from the root objects. If A and B reference each other without any external reference, the mark-and-sweep GC won't be able to mark them as reachable, hence will be selected as candidates for GC.
There are a number of different mark-and-sweep implementations (naive mark-and-sweep, tri-colour etc). But the fundamental idea is the same. If an object cannot be reached from the root by direct/indirect references, it will be garbage collected.
There is a number of GCs. In the Young Generation, there is a copy collector.
What this does is find all the objects which are referenced from "root" objects such a thread stacks. e.g. the eden space is copied to a survivor space, and the survivor spaces are copied to each other. Anything left uncopied is cleared away.
This means if you have a bundle of objects which refer to each other and there is no strong reference to any of them, they will be discarded on the next collection. (The exception being soft references where the GC can choose to keep them or not)
I am reading some materials about garbage collection in Java in order to get to know more deeply what really happens in GC process.
I came across on the mechanism called "card table". I've Googled for it and haven't found comprehensive information. Most of explanations are rather shallow and describes it like some magic.
My question is: How card table and write barrier works? What is marked in card tables? How then garbage collector knows that particular object is referenced by another object persisted in older generation.
I would like to have some practical imagination about that mechanism, like I was supposed to prepare some simulation.
I don't know whether you found some exceptionally bad description or whether you expect too many details, I've been quite satisfied with the explanations I've seen. If the descriptions are brief and sound simplistic, that's because it really is a rather simple mechanism.
As you apparently already know, a generational garbage collector needs to be able to enumerate old objects that refer to young objects. It would be correct to scan all old objects, but that destroys the advantages of the generational approach, so you have to narrow it down. Regardless of how you do that, you need a write barrier - a piece of code executed whenever a member variable (of a reference type) is assigned/written to. If the new reference points to a young object and it's stored in an old object, the write barrier records that fact for the garbage collect. The difference lies in how it's recorded. There are exact schemes using so-called remembered sets, a collection of every old object that has (had at some point) a reference to a young object. As you can imagine, this takes quite a bit of space.
The card table is a trade-off: Instead of telling you which objects exactly contains young pointers (or at least did at some point), it groups objects into fixed-sized buckets and tracks which buckets contain objects with young pointers. This, of course, reduces space usage. For correctness, it doesn't really matter how you bucket the objects, as long as you're consistent about it. For efficiency, you just group them by their memory address (because you have that available for free), divided by some larger power of two (to make the division a cheap bitwise operation).
Also, instead of maintaining an explicit list of buckets, you reserve some space for each possible bucket up-front. Specifically, there is an array of N bits or bytes, where N is the number of buckets, so that the ith value is 0 if the ith bucket contains no young pointers, or 1 if it does contain young pointers. This is the card table proper. Typically this space is allocated and freed along with a large block of memory used as (part of) the heap. It may even be embedded in the start of the memory block, if it doesn't need to grow. Unless the entire address space is used as heap (which is very rare), the above formula gives numbers starting from start_of_memory_region >> K instead of 0, so to get an index into the card table you have to subtract the start of the start address of the heap.
In summary, when the write barrier finds that the statement some_obj.field = other_obj; stores a young pointer in an old object, it does this:
card_table[(&old_obj - start_of_heap) >> K] = 1;
Where &old_obj is the address of the object that now has a young pointer (which is already in a register because it was just determined to refer to an old object).
During minor GC, the garbage collector looks at the card table to determine which heap regions to scan for young pointers:
for i from 0 to (heap_size >> K):
if card_table[i]:
scan heap[i << K .. (i + 1) << K] for young pointers
Sometime ago I have written an article explaining mechanics of young collection in HotSpot JVM.
Understanding GC pauses in JVM, HotSpot's minor GC
Principle of dirty card write-barrier is very simple. Each time when program modifies reference in memory, it should mark modified memory page as dirty. There is a special card table in JVM and each 512 byte page of memory has associated one byte entry in card table.
Normally collection of all references from old space to young would require scanning through all objects in old space. That is why we need write-barrier. All objects in young space have been created (or relocated) since last reset of write-barrier, so non-dirty pages cannot have references into young space. This means we can scan only object in dirty pages.
For anyone who is looking for a simple answer:
In JVM, the memory space of objects is broken down into two spaces:
Young generation (space): All new allocations (objects) are created inside this space.
Old generation (space): This is where long lived objects exist (and probably die)
The idea is that, once an object survives a few garbage collection, it is more likely to survive for a long time. So, objects that survive garbage collection for more than a threshold, will be promoted to old generation. The garbage collector runs more frequently in the young generation and less frequently in the old generation. This is because most objects live for a very short time.
We use generational garbage collection to avoid scanning of the whole memory space (like Mark and Sweep approach). In JVM, we have a minor garbage collection which is when GC runs inside the young generation and a major garbage collection (or full GC) which encompasses garbage collection of both young and old generations.
When doing minor garbage collection, JVM follows every reference from the live roots to the objects in the young generation, and marks those objects as live, which excludes them from the garbage collection process. The problem is that there may be some references from the objects in the old generation to the objects in young generation, which should be considered by GC, meaning those objects in young generation that are referenced by objects in old generation should also be marked as live and excluded from the garbage collection process.
One approach to solve this problem is to scan all of the objects in the old generation and find their references to young objects. But this approach is in contradiction with the idea of generational garbage collectors. (Why we broke down our memory space into multiple generations in the first place?)
Another approach is using write barriers and card table. When an object in old generation writes/updates a reference to an object in the young generation, this action goes through something called write barrier. When JVM sees these write barriers, it updates the corresponding entry in the card table. Card table is a table, which each one of its entries correspond to 512 bytes of the memory. You can think of it as an array containing 0 and 1 items. A 1 entry means there is an object in the corresponding area of the memory which contains references to objects in young generation.
Now, when minor garbage collection is happening, first every reference from the live roots to young objects are followed and the referenced objects in young generation will be marked as live. Then, instead of scanning all of the old object to find references to the young objects, the card table is scanned. If GC finds any marked area in the card table, it loads the corresponding object and follows its references to young objects and marks them as live either.
Suppose there is an object a of class A, which holds a reference to another object b of class B. And this is the only reference to b. So now, if all references to a is removed, then a is ready to GC. Does this mean that b is also ready to get garbage collected? because, though b has a reference ( inside a ), it is unreachable, because a is unreachable.
So how exactly does this scenario works? I mean the order of garbage collection.
Once an object is unreachable from a root, it will be collected. See this question for an explanation of GC roots.
Entire subgraphs will be collected (as you describe) presuming no node within that subgraph may be reached.
Java (and .NET) use mark and sweep garbage collection which deals with this kind of problem.
Reference count-based systems (such as C++'s std::shared_ptr<T>) may fail in the case of circular dependencies that remain unreachable. This is not a problem for Java/.NET GC.
Java GC is smart enough to collect islands of isolated objects though they maybe pointing to each other. Hence, b also becomes eligible for garbage collection. The point to note here is that although you have a reference to b it's not live in the sense that it cannot be reached from your program's root.
It depends on the GC. A JVM can be told to use different GC's and typically uses 3 GC's as one (eden, copy, markcompact).
In any typical GC and in refcounting the situation you described is handled cleanly, both objs are collected. Think of it in 2 stages: first "a" gets noticed and collected then "b" gets noticed and collected. Again: the specific means of noticing depends on the GC.
Even if the objects reference internally to each other, and they do not have a reachable reference from program, they will be eligible for GC. THere is a good explanation with diagrams here
http://www.thejavageek.com/2013/06/22/how-do-objects-become-eligible-for-garbage-collection/
That is exactly the point of GC. Since b is unreachable from main thread, it will be garbage collected. It is not just the count that matters.
how does the garbage collector in java determine that objects are no longer referenced by the program?
It depends on the VM but there are a number of ways it could be done.
Check this out.
Easy way to explain how GC works...
How GC works ?
Reference :
Fig : General Collection of Object
Fig : Memory Collection of Objects
Here's a previous question on much the same subject: logic of Garbage collector in java
The link from there (which I now want to read for myself!) is: http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html
JVM maintains a map of all referenced objects.
Every GC cycle (there are a number of GC methods in java, train, mark and sweep etc.) the entire list of object references are traversed (NOTE object references live in stack, data lives in heap) and all the object references that are no longer referenced are marked as ready to be garbage collected/are garbage collected.
This is a simplified way of understanding GC, most developers don't need to know the internals of the GC process though; but it's good to have some understanding.
Here are some links that might interest you:
http://chaoticjava.com/posts/how-does-garbage-collection-work/
http://java.sun.com/docs/hotspot/gc1.4.2/
http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html
http://www.oracle.com/technetwork/java/javase/tech/ts-3153-coomes-19899-dsf-150093.pdf#search=%22garbage%20collection%22
Hope this helps...