JDK-8150994 : UseParallelGC fails with UseDynamicNumberOfGCThreads with specjbb2005
  • Type: Bug
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: 8u401,9
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2016-03-01
  • Updated: 2025-06-09
  • Resolved: 2016-05-02
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9 b120Fixed
Related Reports
Relates :  
Relates :  
Description
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0xfffffff8c72271bc, pid=24268, tid=35
#
# JRE version: Java(TM) SE Runtime Environment (9.0) (build 9-internal+0-2015-12-10-224000.jmasamit.jdk9-full-test)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (9-internal+0-2015-12-10-224000.jmasamit.jdk9-full-test, mixed mode, tiered, compressed oops, parallel gc, solaris-sparc)
# Problematic frame:
# V  [libjvm.so+0xf271bc]  void ParCompactionManager::push_recycled_stack_index(unsigned)+0x54
#
# Core dump will be written. Default location: /aurora/sandbox/refworkload/benchmarks/specjbb2005/core or core.24268
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
#
Comments
URL: http://hg.openjdk.java.net/jdk9/jdk9/hotspot/rev/4c3ae95327db User: lana Date: 2016-05-25 17:36:48 +0000
25-05-2016

URL: http://hg.openjdk.java.net/jdk9/hs/hotspot/rev/4c3ae95327db User: jmasa Date: 2016-05-02 18:56:13 +0000
02-05-2016

An alternate fix would have made the region stacks a part of the DrainStacksCompactionTask. I think that would work but would need some additional experimentation and would maintain the current tasking structure which from my performance testing does not offer any benefit. I prefer the simplification and a more general fix (not part of this change) for the possible bottleneck at the start of the compaction.
13-04-2016

The original list of task for the UseParallelGC compaction was Region draining tasks Dense prefix update tasks Stealing tasks for region draining The parallel compaction moves data into their new regions from their original regions with each GC thread getting a new region to fill. The list of regions that are ready to fill is calculated during the summary phase of the compaction and each GC thread is given a subset of those regions. The Region draining tasks fills a ready region from its preassigned list and puts empty regions on its list of ready regions. These tasks continue until their list of ready regions is empty. A GC thread's whose ready list went dry would do Dense prefix updates (regions in the dense prefix are not moved but their pointers need to be updated for any objects that are moved). Lastly the Stealing tasks are executed and steal ready regions from other GC threads. This original organization was done because it was recognized that the original set of ready regions could be small and the parallelism would be limited until the ready region lists grow. The idea was work on the ready regions in order to add more regions to the ready list. Those GC threads that did not free up more region for its own list would do dense prefix work while other GC threads continued to create empty regions for filling. Eventually all the dense prefix work would be done and all the GC threads would go to the Stealing tasks to finish up the parallel part of the compaction. This change reduces the tasks to Dense prefix update tasks Stealing tasks for region draining (which also does the filling of the preallocated ready regions). A requirement of the original 3 kinds of tasks implementation was that the all the preloaded ready to fill regions have to be processed. With the UseParallelGC the parallel GC workers did not necessarily each get a Draining task. If there are GC threads A, B and C and Draining tasks 1, 2, and 3, GC thread A could do all three tasks while GC thread B and C were still getting started. Because of that the original implementation had stacks of ready regions and when GC thread A got a task to execute, it would get one of these stacks to empty. When GC thread A was finished, it would add the now empty stack to a list to be reused later. If GC thread A got another task to execute, it would get a different stack. During the execution of the Stealing tasks the GC threads would get a stack to use during the stealing. The cause of this bug was that the coordination of putting the empty region stacks onto the list for later use during by the Stealing task was not adequately synchronized. The solution is to remove the original Draining tasks and to do the initial draining and stealing in one task so that the ready region stacks do not have to be re-used. Creation of more ready regions for filling (and stealing) may be slowed. There are specific optimizations that can be implemented to deal with that problem more generally.
11-04-2016