JDK-6820167 : GCALotAtAllSafepoints + FullGCALot(ScavengeALot) options crash JVM
  • Type: Bug
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: hs15
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2009-03-20
  • Updated: 2011-03-07
  • Resolved: 2011-03-07
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 6 JDK 7 Other
6u18Fixed 7Fixed hs16Fixed
Related Reports
Relates :  
Relates :  
Description
SPECjbb2005 intermittently crashes VM when started with 
-XX:+GCALotAtAllSafepoints -XX:+ScavengeALot(or -XX:+FullGCALot) options.

There are two different assertions to fail.

1. In the case CMS GC is used (-XX:+UseConcMarkSweepGC) the following assertion fails. 
> #  Internal Error (/export/users2/rbouchma/ws/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp:71), pid=6723, tid=2305843011631592064
> #  Error: assert(Thread::current()->is_Java_thread(),"just checking")

2. The second assertion

> #  Error: assert(!Heap_lock->owned_by_self(),"this thread should not own the Heap_lock")

fails in two different locations depending on GC selected:

> hotspot/src/share/vm/memory/genCollectedHeap.cpp:744
> hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp:717

Comments
SUGGESTED FIX It was pointed out in a code review from tonyp (received after this change went to the presses) that the fields and accessors related to *skip_gcalot* should really be DEBUG_ONLY() rather than NOT_PRODUCT(). This clean-up will be rolled into a subsequent fix by this author.
11-06-2009

EVALUATION http://hg.openjdk.java.net/jdk7/hotspot-gc/hotspot/rev/821269eca479
11-06-2009

SUGGESTED FIX Here's an alternative suggested fix (under test and review):- --- old/src/share/vm/memory/gcLocker.hpp Thu Jun 11 12:18:34 2009 +++ new/src/share/vm/memory/gcLocker.hpp Thu Jun 11 12:18:34 2009 @@ -242,6 +242,31 @@ #endif }; +// A SkipGCALot object is used to elide the usual effect of gc-a-lot +// over a section of execution by a thread. Currently, it's used only to +// prevent re-entrant calls to GC. +class SkipGCALot : public StackObj { + private: + bool _saved; + Thread* _t; + + public: +#ifdef ASSERT + SkipGCALot(Thread* t) : _t(t) { + _saved = _t->skip_gcalot(); + _t->set_skip_gcalot(true); + } + + ~SkipGCALot() { + assert(_t->skip_gcalot(), "Save-restore protocol invariant"); + _t->set_skip_gcalot(_saved); + } +#else + SkipGCALot(Thread* t) { } + ~SkipGCALot() { } +#endif +}; + // JRT_LEAF currently can be called from either _thread_in_Java or // _thread_in_native mode. In _thread_in_native, it is ok // for another thread to trigger GC. The rest of the JRT_LEAF --- old/src/share/vm/runtime/interfaceSupport.cpp Thu Jun 11 12:18:36 2009 +++ new/src/share/vm/runtime/interfaceSupport.cpp Thu Jun 11 12:18:35 2009 @@ -66,11 +66,14 @@ void InterfaceSupport::gc_alot() { Thread *thread = Thread::current(); - if (thread->is_VM_thread()) return; // Avoid concurrent calls + if (!thread->is_Java_thread()) return; // Avoid concurrent calls // Check for new, not quite initialized thread. A thread in new mode cannot initiate a GC. JavaThread *current_thread = (JavaThread *)thread; if (current_thread->active_handles() == NULL) return; + // Short-circuit any possible re-entrant gc-a-lot attempt + if (thread->skip_gcalot()) return; + if (is_init_completed()) { if (++_fullgc_alot_invocation < FullGCALotStart) { --- old/src/share/vm/runtime/thread.cpp Thu Jun 11 12:18:37 2009 +++ new/src/share/vm/runtime/thread.cpp Thu Jun 11 12:18:37 2009 @@ -127,6 +127,7 @@ debug_only(_owned_locks = NULL;) debug_only(_allow_allocation_count = 0;) NOT_PRODUCT(_allow_safepoint_count = 0;) + NOT_PRODUCT(_skip_gcalot = false;) CHECK_UNHANDLED_OOPS_ONLY(_gc_locked_out_count = 0;) _jvmti_env_iteration_count = 0; _vm_operation_started_count = 0; @@ -784,7 +785,6 @@ // We could enter a safepoint here and thus have a gc InterfaceSupport::check_gc_alot(); } - #endif } #endif --- old/src/share/vm/runtime/thread.hpp Thu Jun 11 12:18:39 2009 +++ new/src/share/vm/runtime/thread.hpp Thu Jun 11 12:18:39 2009 @@ -191,6 +191,9 @@ NOT_PRODUCT(int _allow_safepoint_count;) // If 0, thread allow a safepoint to happen debug_only (int _allow_allocation_count;) // If 0, the thread is allowed to allocate oops. + // Used by SkipGCALot class. + NOT_PRODUCT(bool _skip_gcalot;) // Should we elide gc-a-lot? + // Record when GC is locked out via the GC_locker mechanism CHECK_UNHANDLED_OOPS_ONLY(int _gc_locked_out_count;) @@ -308,6 +311,11 @@ bool is_gc_locked_out() { return _gc_locked_out_count > 0; } #endif // CHECK_UNHANDLED_OOPS +#ifndef PRODUCT + bool skip_gcalot() { return _skip_gcalot; } + void set_skip_gcalot(bool v) { _skip_gcalot = v; } +#endif + public: // Installs a pending exception to be inserted later static void send_async_exception(oop thread_oop, oop java_throwable); --- old/src/share/vm/runtime/vmThread.cpp Thu Jun 11 12:18:41 2009 +++ new/src/share/vm/runtime/vmThread.cpp Thu Jun 11 12:18:41 2009 @@ -531,6 +531,7 @@ Thread* t = Thread::current(); if (!t->is_VM_thread()) { + SkipGCALot sgcalot(t); // avoid re-entrant attempts to gc-a-lot // JavaThread or WatcherThread t->check_for_valid_safepoint_state(true);
08-06-2009

EVALUATION Under test and review.
08-06-2009