8038822: java/lang/management/MemoryMXBean/LowMemoryTest2.sh still fails with OutOfMemoryError: Metaspace
authormtobiass
Fri, 04 Apr 2014 13:01:26 +0200
changeset 23721 83da5b498504
parent 23720 7d5147c21927
child 23722 877a047171bb
8038822: java/lang/management/MemoryMXBean/LowMemoryTest2.sh still fails with OutOfMemoryError: Metaspace Summary: Force a GC when usage above threshold. Add more logging. Reviewed-by: dfuchs
jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java
jdk/test/java/lang/management/MemoryMXBean/MemoryUtil.java
--- a/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java	Fri Apr 04 19:32:53 2014 +0400
+++ b/jdk/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java	Fri Apr 04 13:01:26 2014 +0200
@@ -64,6 +64,11 @@
     // low memory notification
 
     static class BoundlessLoaderThread extends ClassLoader implements Runnable {
+        private final List<MemoryPoolMXBean> pools;
+
+        public BoundlessLoaderThread(List<MemoryPoolMXBean> pools) {
+            this.pools = pools;
+        }
 
         static int count = 100000;
 
@@ -139,26 +144,29 @@
          * Then wait for the memory threshold notification to be received.
          */
         public void run() {
-            List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
-            boolean thresholdExceeded = false;
-
             // Load classes until MemoryPoolMXBean.getUsageThresholdCount() > 0
-            while (!thresholdExceeded) {
-                // the classes are small so we load 10 at a time
-                for (int i=0; i<10; i++) {
-                    loadNext();
-                }
+            boolean isThresholdCountSet = false;
+            try {
+                while (!isThresholdCountSet) {
+                    // the classes are small so we load 10 at a time
+                    for (int i=0; i<10; i++) {
+                        loadNext();
+                    }
 
-                // check if the threshold has been exceeded
-                for (MemoryPoolMXBean p : pools) {
-                    if (p.getType() == MemoryType.NON_HEAP &&
-                        p.isUsageThresholdSupported() &&
-                        p.getUsageThresholdCount() > 0)
-                    {
-                        thresholdExceeded = true;
-                        break;
+                    if (isAnyUsageAboveThreshold(pools)) {
+                        // UsageThresholdCount is only updated during GC.
+                        // Force GC to update counters.
+                        // If we don't force a GC we may get an
+                        // OutOfMemoryException before the counters are updated.
+                        System.out.println("Force GC");
+                        System.gc();
                     }
+                    isThresholdCountSet = isAnyThresholdCountSet(pools);
                 }
+            } catch (OutOfMemoryError e) {
+                e.printStackTrace();
+                MemoryUtil.printMemoryPools(pools);
+                throw e;
             }
 
             System.out.println("thresholdExceeded. Waiting for notification");
@@ -168,16 +176,39 @@
                 } catch (InterruptedException x) {}
             }
         }
+
+        private boolean isAnyUsageAboveThreshold(List<MemoryPoolMXBean> pools) {
+            for (MemoryPoolMXBean p : pools) {
+                if (p.isUsageThresholdExceeded()) {
+                    System.out.println("isAnyUsageAboveThreshold is true for " + p.getName());
+                    MemoryUtil.printMemoryPool(p);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private boolean isAnyThresholdCountSet(List<MemoryPoolMXBean> pools) {
+            for (MemoryPoolMXBean p : pools) {
+                if (p.getUsageThresholdCount() > 0) {
+                    System.out.println("isAnyThresholdCountSet is true for " + p.getName());
+                    MemoryUtil.printMemoryPool(p);
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     public static void main(String args[]) {
-        List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
+        // The pools list will only contain the pools that we are interested in.
+        List<MemoryPoolMXBean> pools = new ArrayList<MemoryPoolMXBean>();
 
         // Set threshold of 80% of all NON_HEAP memory pools
         // In the Hotspot implementation this means we should get a notification
         // if the CodeCache or metaspace fills up.
 
-        for (MemoryPoolMXBean p : pools) {
+        for (MemoryPoolMXBean p : ManagementFactory.getMemoryPoolMXBeans()) {
             if (p.getType() == MemoryType.NON_HEAP && p.isUsageThresholdSupported()) {
 
                 // set threshold
@@ -190,6 +221,7 @@
                 long threshold = (max * 80) / 100;
 
                 p.setUsageThreshold(threshold);
+                pools.add(p);
 
                 System.out.println("Selected memory pool for low memory " +
                         "detection.");
@@ -209,7 +241,7 @@
 
         // Start the thread loading classes
 
-        Thread thr = new Thread(new BoundlessLoaderThread());
+        Thread thr = new Thread(new BoundlessLoaderThread(pools));
         thr.start();
 
         // Wait for the thread to terminate
--- a/jdk/test/java/lang/management/MemoryMXBean/MemoryUtil.java	Fri Apr 04 19:32:53 2014 +0400
+++ b/jdk/test/java/lang/management/MemoryMXBean/MemoryUtil.java	Fri Apr 04 13:01:26 2014 +0200
@@ -54,6 +54,8 @@
             pool.getUsage());
         System.out.println(INDENT + "Threshold: " +
             (pool.isUsageThresholdSupported() ? pool.getUsageThreshold() : -1));
+        System.out.println(INDENT + "ThresholdCount: " +
+            (pool.isUsageThresholdSupported() ? pool.getUsageThresholdCount() : -1));
         System.out.print(INDENT + "Manager = [");
         String[] mgrs = pool.getMemoryManagerNames();
         for (int i = 0; i < mgrs.length; i++) {