AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |
Back to Blog
Azul openjdk shenandoah9/28/2023 All the frames below that are basically static and don't change-they can safely be scanned concurrently by garbage collection threads. The central observation is that all the thread stack's action happens in the top-most frame: The currently executed method. How can we improve the situation and process thread stacks concurrently? We do so by utilizing a mechanism called stack watermarks (originally implemented by ZGC developers). Concurrent thread processing in OpenJDK 17 All of that processing is done while the application is stopped, so it affects the application's overall end-to-end latency. Smallish workloads (few threads with small stacks) would probably take very few milliseconds to scan, but large workloads- application servers, I'm looking at you!-can easily take several dozens of milliseconds to process. Scanning and processing threads stacks takes time. Invoking a garbage collection barrier for every local variable or register access quicky runs into performance problems. It is too late, at that point, to pass the garbage collection barrier. We need to do so at a pause because garbage collection load barriers normally act when loading the reference from the heap (for example into the local variable or register), which means local variables or registers cannot have object references in the state that requires a GC intervention. ![]() Likewise, when evacuating reachable objects into empty regions, we need to update all references on thread stacks to point to the new object locations. When we're done, we resume execution and traverse the graph of reachable objects, starting from the references that we found during the initial thread scan. We do so at a GC pause (safepoint) because we need a consistent state of the stack at mark start, without the thread's execution concurrently messing with the stack. When a garbage collection cycle is initiated, we first scan all of the threads' stacks to seed marking queues with the references that we find on stacks. Most importantly, in the context of Java garbage collection, it holds references to heap objects (e.g., local variables to reference typed objects). What is thread processing and why do we need to stop the application for it? Java programs are executed in threads, and each thread owns a stack: A list of stack frames, each frame holding local variables, monitors, and other information related to the currently executed method. ![]() ![]() Processing thread stacks concurrently gives us reliable sub-millisecond pauses in JDK 17. This article introduces the new concurrent thread-stack processing in Shenandoah GC. The remaining garbage collection operation under pause was thread-stack processing, which we've solved in JDK 17. In JDK 14, we implemented concurrent class unloading, and in JDK 16, we added concurrent reference processing, both of which further reduced pause times in those garbage collection operations. This version was eventually backported to JDK 11. In JDK 12, we released the original Shenandoah garbage collector, which implements concurrent heap evacuation, which solved the major problem of cleaning (potentially large) heaps without stopping the application. Our primary motivation for the Shenandoah OpenJDK garbage collection (GC) project is to reduce garbage collection pause times.
0 Comments
Read More
Leave a Reply. |