United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: 6820167 GCALotAtAllSafepoints + FullGCALot(ScavengeALot) options crash JVM
6820167 : GCALotAtAllSafepoints + FullGCALot(ScavengeALot) options crash JVM

Details
Type:
Bug
Submit Date:
2009-03-20
Status:
Closed
Updated Date:
2011-03-07
Project Name:
JDK
Resolved Date:
2011-03-07
Component:
hotspot
OS:
generic
Sub-Component:
gc
CPU:
generic
Priority:
P4
Resolution:
Fixed
Affected Versions:
hs15
Fixed Versions:
hs16

Related Reports
Backport:
Backport:
Relates:
Relates:

Sub Tasks

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
EVALUATION

http://hg.openjdk.java.net/jdk7/hotspot-gc/hotspot/rev/821269eca479
                                     
2009-06-11
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.
                                     
2009-06-11
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);
                                     
2009-06-08
EVALUATION

Under test and review.
                                     
2009-06-08



Hardware and Software, Engineered to Work Together