2
votes

I read yesterday about garbage collection and I don't understand some concepts about it. I've read that for minor collection usually is using copying technique to move reachable objects to survivor space and for major collection it's using often mark and sweep.

The first thing I didn't understand is that garbage collector starts from gc roots and moves along the graph to detect live instances, but how does it know which object is young and which object is old? How does it know which memory area object resides in?

The second thing is that if we're doing only minor collection, how the gc knows if object in young generation is not referenced by objects in old generation or by static reference from method area?

The last thing is that after mark and sweep sometimes compaction is done. How does gc know which references to the moved objects have to be updated? If we have a program with thousands of threads with huge frame stacks and gigabytes of heap used? Does it have some internal structures that have that info in form of map or something?

Thanks!

3

3 Answers

1
votes

YoungGen/OldGen & PermGen are the three areas where the Java Heap resides. The JVM is well versed with the boundaries of each.

  1. While collecting the garbage the GC first decides on which space to run and then identifies the GC roots of each object in that space. Whether an Object is young or old is specified by the Space in which it resides in the Heap. The GC maintains the state of each Object too like how many GC cycles each object has survived which gives the GC an estimation whether the time is appropriate to move an object from Young to Old.

  2. An Object Graph decides if a young Gen Object is referenced by an Old Gen reference.

  3. If an Object is compacted the Reference is also updated. This also happens when Objects move from Young > Old Gen.

1
votes

The answer depends upon the GC algorithm, so you will find some variation in answers.

how does GC know which object is young and which object is old? How does it know which memory area object resides in?

The memory address of the object will answer that as each region tends to be fixed in location. Resizing is possible, but that will only occur when the JVM has paused all work threads. Remember also that the G1 collector does not have generations, so the answer does vary on the algorithm being used.

How the gc knows if object in young generation is not referenced by objects in old generation or by static reference from method area?

Some GC algorithms will perform a full scan of all objects in the heap. Others rely on the observation that the number of refs going from old to young gen is relatively low, so the JVM tracks them and uses them as roots for marking purposes. The mechanism for this is usually a score card system, and is the reason why with some of the GC algorithms having a very large ancestor space can slow down the GC of the young space. Because every score card for every object has to be checked to see if it could have a pointer back to the young gen.

The last thing is that after mark and sweep sometimes compaction is done. How does gc know which references to the moved objects have to be updated?

Again, the answer does vary as JVMs are allowed to vary these details. Some algorithms used double indirection so that the pointers are very easy to locate and update. That involves storing a large index for every object. However that has been shown to slow down the user code when GC is not running as the running code had to keep looking up where the object actually was, so yes some GC algorithms do track the references.

Azul uses a very clever mechanism where it invalidates pages of memory and stores a redirection map that is accessed in the trap handler code. Thus it only needs to store the address of objects that have been moved. While other GC algorithms track the information while scanning the live objects. After all, we do not need the information for the dead ones.

0
votes
  1. Every time GC checks whether an object can be collected, it increments a counter in the object, which tells it how many times that object had been visited by GC. That's the easiest way to tell when an object needs to be moved from the young generation to the tenured generation. But as for knowing which area an object is in, the address of the object can be used to calculate it. (E.g. the JVM will just say memory addresses between 0-100 are the young generation, 101+ is the tenured generation.)
  2. Even during a minor collection the entire object graph is traversed to check references. At least theoretically that's what happens, there will be some optimisations in practice. But the general idea is this.
  3. Since the first step is to build a graph of references, that information is still available at the compaction stage. But yeah, compaction of gigabyte-size heaps takes a long time.