Relates :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
When a concurrent System.gc request is made, the current intent is that it starts a new cycle if one is not already in progress, and then waits until the now in-progress cycle completes. To accomplish this, when a concurrent System.gc request is made, the VMOp epilogue waits for the current cycle to complete. That wait is applied both when the VMOp performed the initial mark pause and when the VMOp skipped the GC because there was already a concurrent cycle in progress. However, things can go wrong if two threads simultaneously request such a GC. Assume there is not already a cycle in progress or some other reason for a request to fail (such as GCLocker being active). Assume that each thread (A and B) captures the same total_collections() and old_marking_cycles_started() counter values. Thread A executes its VMOp first, performing the initial mark pause in the safepoint, and increments the total_collections() and old_marking_cycles_started() counters. Once the safepoint is complete, thread A waits in the VMOp epilogue for the concurrent cycle to complete. All is good here. Thread B executes its VMOp second. Its VMOp prologue sees that total_collections() has changed, so skips any further processing of the VMOp (including the wait in the epilogue). Returning to try_collect, it sees that old_marking_cycles_started() has changed and returns immediately, without waiting for the completion of the cycle started by thread A. The rationale for returning immediately (per the associated comment) is "A Full GC happened ... No point in starting a new cycle given that the whole heap was collected anyway." But this doesn't account for the possibility that marking was started for a concurrent collection and thread B should wait for it to complete.
|