Path: blob/master/test/jdk/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java
41155 views
/*1* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 4959889 699296826* @summary Basic unit test of memory management testing:27* 1) setCollectionUsageThreshold() and getCollectionUsageThreshold()28* 2) test notification emitted for two different memory pools.29*30* @author Mandy Chung31*32* @library /test/lib33* @modules jdk.management34* @build CollectionUsageThreshold MemoryUtil RunUtil35* @requires vm.opt.ExplicitGCInvokesConcurrent == "false" | vm.opt.ExplicitGCInvokesConcurrent == "null"36* @build sun.hotspot.WhiteBox37* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox38* @run main/othervm/timeout=300 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. CollectionUsageThreshold39*/4041import java.util.*;42import java.util.concurrent.*;43import java.util.concurrent.atomic.AtomicInteger;44import javax.management.*;45import javax.management.openmbean.CompositeData;46import java.lang.management.*;47import static java.lang.management.MemoryNotificationInfo.*;;48import static java.lang.management.ManagementFactory.*;4950import sun.hotspot.code.Compiler;5152public class CollectionUsageThreshold {53private static final MemoryMXBean mm = getMemoryMXBean();54private static final Map<String, PoolRecord> result = new HashMap<>();55private static boolean trace = false;56private static volatile int numMemoryPools = 1;57private static final int NUM_GCS = 3;58private static final int THRESHOLD = 10;59private static volatile int numGCs = 0;6061// semaphore to signal the arrival of a low memory notification62private static final Semaphore signals = new Semaphore(0);63// barrier for the main thread to wait until the checker thread64// finishes checking the low memory notification result65private static final CyclicBarrier barrier = new CyclicBarrier(2);6667/**68* Run the test multiple times with different GC versions.69* First with default command line specified by the framework.70* Then with GC versions specified by the test.71*/72public static void main(String a[]) throws Throwable {73final String main = "CollectionUsageThreshold$TestMain";74RunUtil.runTestKeepGcOpts(main);75RunUtil.runTestClearGcOpts(main, "-XX:+UseSerialGC");76RunUtil.runTestClearGcOpts(main, "-XX:+UseParallelGC");77RunUtil.runTestClearGcOpts(main, "-XX:+UseG1GC");78}7980static class PoolRecord {81private final MemoryPoolMXBean pool;82private final AtomicInteger listenerInvoked = new AtomicInteger(0);83private volatile long notifCount = 0;84PoolRecord(MemoryPoolMXBean p) {85this.pool = p;86}87int getListenerInvokedCount() {88return listenerInvoked.get();89}90long getNotifCount() {91return notifCount;92}93MemoryPoolMXBean getPool() {94return pool;95}96void addNotification(MemoryNotificationInfo minfo) {97listenerInvoked.incrementAndGet();98notifCount = minfo.getCount();99}100}101102static class SensorListener implements NotificationListener {103@Override104public void handleNotification(Notification notif, Object handback) {105String type = notif.getType();106if (MEMORY_THRESHOLD_EXCEEDED.equals(type) ||107MEMORY_COLLECTION_THRESHOLD_EXCEEDED.equals(type)) {108MemoryNotificationInfo minfo = MemoryNotificationInfo.109from((CompositeData) notif.getUserData());110111MemoryUtil.printMemoryNotificationInfo(minfo, type);112PoolRecord pr = (PoolRecord) result.get(minfo.getPoolName());113if (pr == null) {114throw new RuntimeException("Pool " + minfo.getPoolName() +115" is not selected");116}117if (!MEMORY_COLLECTION_THRESHOLD_EXCEEDED.equals(type)) {118throw new RuntimeException("Pool " + minfo.getPoolName() +119" got unexpected notification type: " +120type);121}122pr.addNotification(minfo);123System.out.println("notifying the checker thread to check result");124signals.release();125}126}127}128129private static class TestMain {130public static void main(String args[]) throws Exception {131if (args.length > 0 && args[0].equals("trace")) {132trace = true;133}134135List<MemoryPoolMXBean> pools = getMemoryPoolMXBeans();136List<MemoryManagerMXBean> managers = getMemoryManagerMXBeans();137138if (trace) {139MemoryUtil.printMemoryPools(pools);140MemoryUtil.printMemoryManagers(managers);141}142143// Find the Old generation which supports low memory detection144for (MemoryPoolMXBean p : pools) {145if (p.isUsageThresholdSupported() && p.isCollectionUsageThresholdSupported()) {146if (p.getName().toLowerCase().contains("perm")) {147// if we have a "perm gen" pool increase the number of expected148// memory pools by one.149numMemoryPools++;150}151PoolRecord pr = new PoolRecord(p);152result.put(p.getName(), pr);153if (result.size() == numMemoryPools) {154break;155}156}157}158if (result.size() != numMemoryPools) {159throw new RuntimeException("Unexpected number of selected pools");160}161162try {163// This test creates a checker thread responsible for checking164// the low memory notifications. It blocks until a permit165// from the signals semaphore is available.166Checker checker = new Checker("Checker thread");167checker.setDaemon(true);168checker.start();169170for (PoolRecord pr : result.values()) {171pr.getPool().setCollectionUsageThreshold(THRESHOLD);172System.out.println("Collection usage threshold of " +173pr.getPool().getName() + " set to " + THRESHOLD);174}175176SensorListener listener = new SensorListener();177NotificationEmitter emitter = (NotificationEmitter) mm;178emitter.addNotificationListener(listener, null, null);179180// The main thread invokes GC to trigger the VM to perform181// low memory detection and then waits until the checker thread182// finishes its work to check for a low-memory notification.183//184// At GC time, VM will issue low-memory notification and invoke185// the listener which will release a permit to the signals semaphore.186// When the checker thread acquires the permit and finishes187// checking the low-memory notification, it will also call188// barrier.await() to signal the main thread to resume its work.189for (int i = 0; i < NUM_GCS; i++) {190invokeGC();191barrier.await();192}193} finally {194// restore the default195for (PoolRecord pr : result.values()) {196pr.getPool().setCollectionUsageThreshold(0);197}198}199System.out.println(RunUtil.successMessage);200}201202203private static void invokeGC() {204System.out.println("Calling System.gc()");205numGCs++;206mm.gc();207208if (trace) {209for (PoolRecord pr : result.values()) {210System.out.println("Usage after GC for: " + pr.getPool().getName());211MemoryUtil.printMemoryUsage(pr.getPool().getUsage());212}213}214}215}216217static class Checker extends Thread {218Checker(String name) {219super(name);220};221@Override222public void run() {223while (true) {224try {225signals.acquire(numMemoryPools);226checkResult();227} catch (InterruptedException | BrokenBarrierException e) {228throw new RuntimeException(e);229}230}231}232private void checkResult() throws InterruptedException, BrokenBarrierException {233for (PoolRecord pr : result.values()) {234if (pr.getListenerInvokedCount() != numGCs) {235fail("Listeners invoked count = " +236pr.getListenerInvokedCount() + " expected to be " +237numGCs);238}239if (pr.getNotifCount() != numGCs) {240fail("Notif Count = " +241pr.getNotifCount() + " expected to be " +242numGCs);243}244245long count = pr.getPool().getCollectionUsageThresholdCount();246if (count != numGCs) {247fail("CollectionUsageThresholdCount = " +248count + " expected to be " + numGCs);249}250if (!pr.getPool().isCollectionUsageThresholdExceeded()) {251fail("isCollectionUsageThresholdExceeded" +252" expected to be true");253}254}255// wait until the main thread is waiting for notification256barrier.await();257System.out.println("notifying main thread to continue - result checking finished");258}259260private void fail(String msg) {261// reset the barrier to cause BrokenBarrierException to avoid hanging262barrier.reset();263throw new RuntimeException(msg);264}265}266}267268269