0

A garbage collection cycle of ZGC has in essential two phases: marking and relocating. During the marking phase in all references to a live object one of the flags marked0 or marked1 is set (the flags are usesd alternatingly by the garbage collection cycles [1]).

For simplicity suppose all objects in the heap are live, i.e. no relocation is needed. (Suppose further that no object is referenced by a finalizer and that no object is created during the gc cycle)

Question: Which flag (i.e. remapped or marked0 / marked1) is set in the references after the garbage collection cycle has finished?

Background: When the application invokes an object, the load barrier checks the flags in the reference and takes action (see the flowchart with the blue shapes in [2]). The remapped flag indicates that the reference is up to date, i.e. the object can be directly accessed by the reference. If the remapped flag is not set, more checking is required, thus decreasing performance of the app. Therefore, it would be desireable, if the garbage collector would set the remapped flag. However, just one of the flags remapped, marked0, marked1 is set at any point in time ([2] "Multi-mapping"). Since in the marking phase marked0 / marked1 is set, I believe, that remapped can't be set by the ZGC garbage collector. What disturbs me is that then performance of the app after the gc cycle would be worser than before the cycle.

[1] https://dinfuehr.github.io/blog/a-first-look-into-zgc

[2] https://www.opsian.com/blog/javas-new-zgc-is-very-exciting

user120513
  • 531
  • 4
  • 12
  • 1
    As far as I understood, the check for the remapped flag is only performed when the garbage collector is in the middle of the relocation phase. When the garbage collector is not in this phase, the multi-mapping trick described earlier applies, which allows to read through the pointer without fiddling with the mark bits. – Holger Jan 13 '20 at 14:17
  • 1
    @Holger when GC is not in the remap phase, it could be in one of the mark phases ( `marked0` or `marked1`), so there could still be a check against _those_ bits. – Eugene Jan 14 '20 at 04:10
  • 1
    @Eugene no, that’s what handled with the multi-mapping trick, which makes the address pointing to the intended data, regardless of the bits. The only thing that needs to be handled, is the remap phase, when the object could have been relocated but the pointer not adapted yet. – Holger Jan 14 '20 at 07:26
  • 1
    @Holger [here](http://www.youtube.com/watch?v=kF_r3GE3zOo&t=14m14s) is where I implied this information. `Bad Color? Yes -> Enter slow path and mark/relocate/remap`. Checking if it is `Bad Color` in the marking phase (because if it is it will be `marked` later as the comment says), requires reading that flag first. – Eugene Jan 14 '20 at 21:15
  • 2
    @Eugene I don’t know whether the four color bits of that video are the same as the three bits discussed in the other article, but anyway, there’s not necessarily a contradiction, as that only describes how a barrier can be implemented, which doesn’t imply that it is always needed. One possible solution could be to branch at a safepoint into either, a barrier-free code fragment or a path with barriers. Each of them will eventually reach another safepoint where either, the gc state is rechecked or a barrier using code is entered unconditionally when no barrier free version has been compiled. – Holger Jan 15 '20 at 08:48
  • 1
    @Holger the bigger problem that I have, is why have that flags then? Why would you need to say "I am in the mark phase now", without ever checking that flag? If this is truly metadata for the GC, when is a GC actually using it? – Eugene Jan 15 '20 at 12:06
  • @Eugene and Holger: Thanks for your comments. I know, the question is very specific and I appreciate every discussion. Also, I think it might be helpful to consider a simple example. Therefore, I reposted the question detailed by an example: https://stackoverflow.com/questions/59753504/undestanding-a-detail-about-the-colour-bits-in-the-zgc-algorithm – user120513 Jan 15 '20 at 14:33
  • @Holger: After a relocation, ZGC defers remapping of the references to the next marking phase (except root references) ([1] "Marking & Relocating objects", penultimate paragraph). So, multimapping doesn't help if the app loads the reference before the next marking phase takes place, because the address will point to the old location on the heap. Therefore, the load barrier always needs to check the colour bits. – user120513 Jan 15 '20 at 14:40
  • Isn’t “before the next marking phase takes place” the same as “being in the relocation phase”? There are only those two phases. – Holger Jan 15 '20 at 15:22
  • 1
    @Eugene when I read that there is a “live map” and a “forwarding table” anyway, I can’t help asking why all these flags are needed too. Especially the “finalizable” flag that would never occur, as objects are finalizable when no reference exist anyway, except for the one that gets special treatment already. The article says that “Shenandoah in comparison stores the forwarding pointer in the object itself”, which somehow makes more sense to me. – Holger Jan 15 '20 at 18:19
  • @Holger: No it isn't the same: After the relocation phase has finished, the whole gc cycle is finished. It will take some time until the next gc cycle runs. In the meantime, the references (except the root references) of the relocated objects point to the old location (and need to be remapped by the load barrier if the app loads the reference between the finished and the next to come gc cycle). – user120513 Jan 17 '20 at 19:41
  • you last comment is incorrect and comes mainly from this part of the first link you posted : `An object is either relocated by a GC thread or an application thread...`. Which thread relocates the object depends on two things : 1) GC has to be in the phase were relocating happens 2) who touches the reference first - application thread or GC thread. Let's say GC is in the needed phase and application thread comes first to the `LoadBarrier`. It will create a copy, relocate it and put the reference into a `ConcurrentMap` (it's actually a forwarding table called). GC thread will do the same thing: – Eugene Jan 22 '20 at 22:34
  • create a copy, and _try_ to place it in that Map. Because such an entry is already there, it will simply back-off: the work has already been done - someone else moved it. It will destroy the copy it made and give up. In my understanding this can only happen when GC is in the relocation phase, that is GC is active. If it is _not_ active, application threads can still alter the "from-space" – Eugene Jan 22 '20 at 22:39
  • @Eugene: Why is it incorrect? I mean, aren't we just considering different situations? To my understanding, you are treating the case when the gc is in the relocation phase and an application thread concurrently accesses an object that is being relocated (and I totally agree with your description of the handling of this case). While I considered the state after a gc cycle has finished and the next gc cycle hasn't started yet. – user120513 Jan 24 '20 at 20:43
  • well in such a case, if the GC is not active _and_ you obviously reach a LoadBarrier - there is not much to be done (also called the _fastpath_ of the barrier). In my understanding, `relocation` phase happens in the `mark` phase, as such when GC is _not_ active - the object has not been relocated yet, so there is no old/new location just yet. That "old" location will appear only when GC actually moved the object. Also in my understanding (I am working on an answer for the past 7 days now), the relocation would be a compareAndExchange of the address of _each_ threads copy of the object: – Eugene Jan 24 '20 at 22:11
  • I mean when in the relocation phase, each thread that reaches the barrier will potentially have to copy the object to the "to-space" and update it's reference to that space, _at the same_ time updating the remaped flag. So that every thread that comes after that can do things on top of that Object that is already in the "to-space". I hope this makes sense. – Eugene Jan 24 '20 at 22:14

0 Answers0