src/share/vm/runtime/synchronizer.cpp

Print this page

        

@@ -939,11 +939,11 @@
   ObjectMonitor* mid;
   int inusetally = 0;
   for (mid = Self->omInUseList; mid != NULL; mid = mid->FreeNext) {
     inusetally++;
   }
-  assert(inusetally == Self->omInUseCount, "inuse count off");
+  assert(inusetally == Self->omInUseCount, "in use count off");
 
   int freetally = 0;
   for (mid = Self->omFreeList; mid != NULL; mid = mid->FreeNext) {
     freetally++;
   }

@@ -1092,36 +1092,40 @@
 // In practice there's no need to clamp or limit the number of
 // monitors on a thread's omFreeList as the only time we'll call
 // omRelease is to return a monitor to the free list after a CAS
 // attempt failed.  This doesn't allow unbounded #s of monitors to
 // accumulate on a thread's free list.
+//
+// Key constraint: all ObjectMonitors on a thread's free list and the global
+// free list must have their object field set to null. This prevents the
+// scavenger -- deflate_idle_monitors -- from reclaiming them.
 
 void ObjectSynchronizer::omRelease(Thread * Self, ObjectMonitor * m,
                                    bool fromPerThreadAlloc) {
   guarantee(m->object() == NULL, "invariant");
-
+  guarantee(((m->is_busy()|m->_recursions) == 0), "freeing in use monitor");
   // Remove from omInUseList
   if (MonitorInUseLists && fromPerThreadAlloc) {
     ObjectMonitor* curmidinuse = NULL;
-    for (ObjectMonitor* mid = Self->omInUseList; mid != NULL;) {
+    bool extracted = false;
+    for (ObjectMonitor* mid = Self->omInUseList; mid != NULL; curmidinuse = mid, mid = mid->FreeNext) {
       if (m == mid) {
         // extract from per-thread in-use-list
         if (mid == Self->omInUseList) {
           Self->omInUseList = mid->FreeNext;
         } else if (curmidinuse != NULL) {
           curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist
         }
+        extracted = true;
         Self->omInUseCount--;
         if (ObjectMonitor::Knob_VerifyInUse) {
           verifyInUse(Self);
         }
         break;
-      } else {
-        curmidinuse = mid;
-        mid = mid->FreeNext;
       }
     }
+    assert(extracted, "Should have extracted from in use list");
   }
 
   // FreeNext is used for both omInUseList and omFreeList, so clear old before setting new
   m->FreeNext = Self->omFreeList;
   Self->omFreeList = m;

@@ -1153,10 +1157,14 @@
   Self->omFreeList = NULL;
   ObjectMonitor * Tail = NULL;
   int Tally = 0;
   if (List != NULL) {
     ObjectMonitor * s;
+    // The thread is going away, the per-thread free monitors
+    // are freed via set_owner(NULL)
+    // Link them to Tail, which will be linked into the global free list
+    // gFreeList below, under the ListLock
     for (s = List; s != NULL; s = s->FreeNext) {
       Tally++;
       Tail = s;
       guarantee(s->object() == NULL, "invariant");
       guarantee(!s->is_busy(), "invariant");

@@ -1170,15 +1178,19 @@
   ObjectMonitor * InUseTail = NULL;
   int InUseTally = 0;
   if (InUseList != NULL) {
     Self->omInUseList = NULL;
     ObjectMonitor *curom;
+    // The thread is going away, however the omInUseList inflated
+    // monitors may still be in use by other threads.
+    // Link them to InUseTail, which will be linked into the global in use list
+    // gOmInUseList below, under the ListLock
     for (curom = InUseList; curom != NULL; curom = curom->FreeNext) {
       InUseTail = curom;
       InUseTally++;
     }
-    assert(Self->omInUseCount == InUseTally, "inuse count off");
+    assert(Self->omInUseCount == InUseTally, "in use count off");
     Self->omInUseCount = 0;
     guarantee(InUseTail != NULL && InUseList != NULL, "invariant");
   }
 
   Thread::muxAcquire(&ListLock, "omFlush");

@@ -1409,18 +1421,18 @@
 // impacts the performance of some applications (e.g., PointBase).
 // Broadly, we want to minimize the # of monitors in circulation.
 //
 // We have added a flag, MonitorInUseLists, which creates a list
 // of active monitors for each thread. deflate_idle_monitors()
-// only scans the per-thread inuse lists. omAlloc() puts all
+// only scans the per-thread in use lists. omAlloc() puts all
 // assigned monitors on the per-thread list. deflate_idle_monitors()
 // returns the non-busy monitors to the global free list.
 // When a thread dies, omFlush() adds the list of active monitors for
 // that thread to a global gOmInUseList acquiring the
 // global list lock. deflate_idle_monitors() acquires the global
 // list lock to scan for non-busy monitors to the global free list.
-// An alternative could have used a single global inuse list. The
+// An alternative could have used a single global in use list. The
 // downside would have been the additional cost of acquiring the global list lock
 // for every omAlloc().
 //
 // Perversely, the heap size -- and thus the STW safepoint rate --
 // typically drives the scavenge rate.  Large heaps can mean infrequent GC,

@@ -1476,26 +1488,25 @@
     deflated = true;
   }
   return deflated;
 }
 
+// Walk a given monitor list, and deflate idle monitors
+// The given list could be a per-thread list or a global list
 // Caller acquires ListLock
-int ObjectSynchronizer::walk_monitor_list(ObjectMonitor** listheadp,
+int ObjectSynchronizer::deflate_monitor_list(ObjectMonitor** listheadp,
                                           ObjectMonitor** freeHeadp,
                                           ObjectMonitor** freeTailp) {
   ObjectMonitor* mid;
   ObjectMonitor* next;
   ObjectMonitor* curmidinuse = NULL;
   int deflatedcount = 0;
 
   for (mid = *listheadp; mid != NULL;) {
     oop obj = (oop) mid->object();
-    bool deflated = false;
-    if (obj != NULL) {
-      deflated = deflate_monitor(mid, obj, freeHeadp, freeTailp);
-    }
-    if (deflated) {
+    if (obj != NULL && deflate_monitor(mid, obj, freeHeadp, freeTailp)) {
+      // if deflate_monitor succeeded,/moribund
       // extract from per-thread in-use-list
       if (mid == *listheadp) {
         *listheadp = mid->FreeNext;
       } else if (curmidinuse != NULL) {
         curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist

@@ -1530,11 +1541,11 @@
 
   if (MonitorInUseLists) {
     int inUse = 0;
     for (JavaThread* cur = Threads::first(); cur != NULL; cur = cur->next()) {
       nInCirculation+= cur->omInUseCount;
-      int deflatedcount = walk_monitor_list(cur->omInUseList_addr(), &FreeHead, &FreeTail);
+      int deflatedcount = deflate_monitor_list(cur->omInUseList_addr(), &FreeHead, &FreeTail);
       cur->omInUseCount-= deflatedcount;
       if (ObjectMonitor::Knob_VerifyInUse) {
         verifyInUse(cur);
       }
       nScavenged += deflatedcount;

@@ -1542,11 +1553,11 @@
     }
 
     // For moribund threads, scan gOmInUseList
     if (gOmInUseList) {
       nInCirculation += gOmInUseCount;
-      int deflatedcount = walk_monitor_list((ObjectMonitor **)&gOmInUseList, &FreeHead, &FreeTail);
+      int deflatedcount = deflate_monitor_list((ObjectMonitor **)&gOmInUseList, &FreeHead, &FreeTail);
       gOmInUseCount-= deflatedcount;
       nScavenged += deflatedcount;
       nInuse += gOmInUseCount;
     }