(Note: This needs to be filled in.)
Changes to the heap's object graph need to be tracked by the GC; such tracking is done via store barriers.
In GC's before G1, tracked stores are done by marking cards.
G1 has a more complex store barrier that (sometimes) logs values involved in the store.
The following reference writes must have store barriers:
- field stores (both instance and static)
- array element stores
- native code stores (JNI, VM code, arraycopy stubs, etc.)
Writes to the stack or registers do not need card marks, because each thread's stack and registers are treated as root sets. In fact, card marks to non-heap locations are impossible, and if attempted may cause unpredictable memory stomps.
Non-heap root elements include:
- compiled stack and registers
- interpreter stack
- handles (both thread local and global)
- certain special C global variables, e.g., the system dictionary
Object fields are marked on the card associated with the base address (header) of the object.
Array element stores are precisely card marked. That is, the address of the element itself determines the card to mark. This is done because arrays (unlike instances) can be large, and it is more efficient to scan parts of arrays for updated elements.
The stores into new objects are not card marked, because they are presumably in the TLAB. For the rare cases where the slow path for TLAB overflow creates a non-TLAB object, the slow path preemptively marks the entire object just before returning down to the compiled code. It is a crucial fact that there is no possible safepoint between this preemptive marking and the compiled block which initializes the object without card marks.
This optimization is controlled by the option ReduceInitialCardMarks.
The method Unsafe.putObject can write a reference to an arbitrary place in the heap. Unusually, this is done without knowledge of the object's status as an instance or array. The card mark is done exactly (like an array) if no information is available about the target object. See