1 /* 2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test TestGarbageCollectorMXBean 26 * @requires vm.gc.Z & !vm.graal.enabled 27 * @summary Test ZGC garbage collector MXBean 28 * @modules java.management 29 * @run main/othervm -XX:+UseZGC -Xms256M -Xmx512M -Xlog:gc TestGarbageCollectorMXBean 256 512 30 * @run main/othervm -XX:+UseZGC -Xms512M -Xmx512M -Xlog:gc TestGarbageCollectorMXBean 512 512 31 */ 32 33 import java.lang.management.ManagementFactory; 34 import java.util.concurrent.atomic.AtomicInteger; 35 import java.util.concurrent.atomic.AtomicLong; 36 import javax.management.Notification; 37 import javax.management.NotificationBroadcaster; 38 import javax.management.NotificationListener; 39 import javax.management.openmbean.CompositeData; 40 41 import com.sun.management.GarbageCollectionNotificationInfo; 42 43 public class TestGarbageCollectorMXBean { 44 public static void main(String[] args) throws Exception { 45 final long M = 1024 * 1024; 46 final long initialCapacity = Long.parseLong(args[0]) * M; 47 final long maxCapacity = Long.parseLong(args[1]) * M; 48 final AtomicInteger cycles = new AtomicInteger(); 49 final AtomicInteger errors = new AtomicInteger(); 50 51 final NotificationListener listener = (Notification notification, Object ignored) -> { 52 final var type = notification.getType(); 53 if (!type.equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { 54 // Ignore 55 return; 56 } 57 58 final var data = (CompositeData)notification.getUserData(); 59 final var info = GarbageCollectionNotificationInfo.from(data); 60 final var name = info.getGcName(); 61 final var id = info.getGcInfo().getId(); 62 final var action = info.getGcAction(); 63 final var cause = info.getGcCause(); 64 final var startTime = info.getGcInfo().getStartTime(); 65 final var endTime = info.getGcInfo().getEndTime(); 66 final var duration = info.getGcInfo().getDuration(); 67 final var memoryUsageBeforeGC = info.getGcInfo().getMemoryUsageBeforeGc().get("ZHeap"); 68 final var memoryUsageAfterGC = info.getGcInfo().getMemoryUsageAfterGc().get("ZHeap"); 69 70 System.out.println(name + " (" + type + ")"); 71 System.out.println(" Id: " + id); 72 System.out.println(" Action: " + action); 73 System.out.println(" Cause: " + cause); 74 System.out.println(" StartTime: " + startTime); 75 System.out.println(" EndTime: " + endTime); 76 System.out.println(" Duration: " + duration); 77 System.out.println(" MemoryUsageBeforeGC: " + memoryUsageBeforeGC); 78 System.out.println(" MemoryUsageAfterGC: " + memoryUsageAfterGC); 79 System.out.println(); 80 81 if (name.equals("ZGC")) { 82 cycles.incrementAndGet(); 83 } else { 84 System.out.println("ERROR: Name"); 85 errors.incrementAndGet(); 86 } 87 88 if (!action.equals("end of major GC")) { 89 System.out.println("ERROR: Action"); 90 errors.incrementAndGet(); 91 } 92 93 if (memoryUsageBeforeGC.getInit() != initialCapacity) { 94 System.out.println("ERROR: MemoryUsageBeforeGC.init"); 95 errors.incrementAndGet(); 96 } 97 98 if (memoryUsageBeforeGC.getUsed() > initialCapacity) { 99 System.out.println("ERROR: MemoryUsageBeforeGC.used"); 100 errors.incrementAndGet(); 101 } 102 103 if (memoryUsageBeforeGC.getCommitted() != initialCapacity) { 104 System.out.println("ERROR: MemoryUsageBeforeGC.committed"); 105 errors.incrementAndGet(); 106 } 107 108 if (memoryUsageBeforeGC.getMax() != maxCapacity) { 109 System.out.println("ERROR: MemoryUsageBeforeGC.max"); 110 errors.incrementAndGet(); 111 } 112 113 if (!cause.equals("System.gc()")) { 114 System.out.println("ERROR: Cause"); 115 errors.incrementAndGet(); 116 } 117 118 if (startTime > endTime) { 119 System.out.println("ERROR: StartTime"); 120 errors.incrementAndGet(); 121 } 122 123 if (endTime - startTime != duration) { 124 System.out.println("ERROR: Duration"); 125 errors.incrementAndGet(); 126 } 127 }; 128 129 // Collect garbage created at startup 130 System.gc(); 131 132 // Register GC event listener 133 for (final var collector : ManagementFactory.getGarbageCollectorMXBeans()) { 134 final NotificationBroadcaster broadcaster = (NotificationBroadcaster)collector; 135 broadcaster.addNotificationListener(listener, null, null); 136 } 137 138 final int minCycles = 5; 139 140 // Run GCs 141 for (int i = 0; i < minCycles; i++) { 142 System.gc(); 143 } 144 145 // Wait at most 60 seconds 146 for (int i = 0; i < 60; i++) { 147 Thread.sleep(1000); 148 if (cycles.get() >= minCycles) { 149 // All events received 150 break; 151 } 152 } 153 154 final int actualCycles = cycles.get(); 155 final int actualErrors = errors.get(); 156 157 System.out.println(" minCycles: " + minCycles); 158 System.out.println("actualCycles: " + actualCycles); 159 System.out.println("actualErrors: " + actualErrors); 160 161 // Verify number of cycle events 162 if (cycles.get() < minCycles) { 163 throw new Exception("Unexpected cycles"); 164 } 165 166 // Verify number of errors 167 if (actualErrors != 0) { 168 throw new Exception("Unexpected errors"); 169 } 170 } 171 }