changeset 1424:cdac7ecd1392

7901968: GC detection should be stricter: make sure finalization had run, make sure GC is silent, etc
author shade
date Tue, 02 May 2017 21:12:36 +0200
parents 2e3213e9e8d4
children fee0ecf0a008
files jmh-core/src/main/java/org/openjdk/jmh/runner/BaseRunner.java
diffstat 1 files changed, 30 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/BaseRunner.java	Tue May 02 20:19:43 2017 +0200
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/BaseRunner.java	Tue May 02 21:12:36 2017 +0200
@@ -321,8 +321,20 @@
                 beforeGcCount += bean.getCollectionCount();
             }
 
-            // this call is asynchronous, should check whether it completes
+            // Run the GC twice, and force finalization before each GCs.
+            System.runFinalization();
             System.gc();
+            System.runFinalization();
+            System.gc();
+
+            // Now make sure GC actually happened. We have to wait for two things:
+            //   a) That at least two collections happened, indicating GC work.
+            //   b) That counter updates have not happened for a while, indicating GC work had ceased.
+            //
+            // Note there is an opportunity window for a concurrent GC to happen before the first
+            // System.gc() call, which would get counted towards our GCs. This race is unresolvable
+            // unless we have GC-specific information about the collection cycles, and verify those
+            // were indeed GCs triggered by us.
 
             final int MAX_WAIT_MSEC = 20 * 1000;
 
@@ -336,6 +348,8 @@
                 return true;
             }
 
+            boolean gcHappened = false;
+
             long start = System.nanoTime();
             while (TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start) < MAX_WAIT_MSEC) {
                 try {
@@ -349,12 +363,24 @@
                     afterGcCount += bean.getCollectionCount();
                 }
 
-                if (afterGcCount > beforeGcCount) {
-                    return true;
+                if (!gcHappened) {
+                    if (afterGcCount - beforeGcCount >= 2) {
+                        gcHappened = true;
+                    }
+                } else {
+                    if (afterGcCount == beforeGcCount) {
+                        // Stable!
+                        return true;
+                    }
+                    beforeGcCount = afterGcCount;
                 }
             }
 
-            out.println("WARNING: System.gc() was invoked but couldn't detect a GC occuring, is System.gc() disabled?");
+            if (gcHappened) {
+                out.println("WARNING: System.gc() was invoked but unable to wait while GC stopped, is GC too asynchronous?");
+            } else {
+                out.println("WARNING: System.gc() was invoked but couldn't detect a GC occurring, is System.gc() disabled?");
+            }
             return false;
         }
         return false;