7036199: Adding a notification to the implementation of GarbageCollectorMXBeans
Add a JMX notification to GarbageCollectorMXBeans Reviewed-by: acorn, mchung
This commit is contained in:
parent
a4dd92fb42
commit
e075dabb40
@ -49,6 +49,7 @@ SUNWprivate_1.1 {
|
||||
Java_sun_management_Flag_setStringValue;
|
||||
Java_sun_management_GarbageCollectorImpl_getCollectionCount;
|
||||
Java_sun_management_GarbageCollectorImpl_getCollectionTime;
|
||||
Java_sun_management_GarbageCollectorImpl_setNotificationEnabled;
|
||||
Java_sun_management_GcInfoBuilder_fillGcAttributeInfo;
|
||||
Java_sun_management_GcInfoBuilder_getLastGcInfo0;
|
||||
Java_sun_management_GcInfoBuilder_getNumGcExtAttributes;
|
||||
|
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.management;
|
||||
|
||||
import javax.management.Notification;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.CompositeDataView;
|
||||
import javax.management.openmbean.CompositeType;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import sun.management.GarbageCollectionNotifInfoCompositeData;
|
||||
|
||||
/**
|
||||
* The information about a garbage collection
|
||||
*
|
||||
* <p>
|
||||
* A garbage collection notification is emitted by {@link GarbageCollectorMXBean}
|
||||
* when the Java virtual machine completes a garbage collection action
|
||||
* The notification emitted will contain the garbage collection notification
|
||||
* information about the status of the memory:
|
||||
* <u1>
|
||||
* <li>The name of the garbage collector used perform the collection.</li>
|
||||
* <li>The action performed by the garbage collector.</li>
|
||||
* <li>The cause of the garbage collection action.</li>
|
||||
* <li>A {@link GcInfo} object containing some statistics about the GC cycle
|
||||
(start time, end time) and the memory usage before and after
|
||||
the GC cycle.</li>
|
||||
* </u1>
|
||||
*
|
||||
* <p>
|
||||
* A {@link CompositeData CompositeData} representing
|
||||
* the {@code GarbageCollectionNotificationInfo} object
|
||||
* is stored in the
|
||||
* {@linkplain javax.management.Notification#setUserData userdata}
|
||||
* of a {@linkplain javax.management.Notification notification}.
|
||||
* The {@link #from from} method is provided to convert from
|
||||
* a {@code CompositeData} to a {@code GarbageCollectionNotificationInfo}
|
||||
* object. For example:
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* Notification notif;
|
||||
*
|
||||
* // receive the notification emitted by a GarbageCollectorMXBean and set to notif
|
||||
* ...
|
||||
*
|
||||
* String notifType = notif.getType();
|
||||
* if (notifType.equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {
|
||||
* // retrieve the garbage collection notification information
|
||||
* CompositeData cd = (CompositeData) notif.getUserData();
|
||||
* GarbageCollectionNotificationInfo info = GarbageCollectionNotificationInfo.from(cd);
|
||||
* ....
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* <p>
|
||||
* The type of the notification emitted by a {@code GarbageCollectorMXBean} is:
|
||||
* <ul>
|
||||
* <li>A {@linkplain #GARBAGE_COLLECTION_NOTIFICATION garbage collection notification}.
|
||||
* <br>Used by every notification emitted by the garbage collector, the details about
|
||||
* the notification are provided in the {@linkplain #getGcAction action} String
|
||||
* <p></li>
|
||||
* </ul>
|
||||
**/
|
||||
|
||||
public class GarbageCollectionNotificationInfo implements CompositeDataView {
|
||||
|
||||
private final String gcName;
|
||||
private final String gcAction;
|
||||
private final String gcCause;
|
||||
private final GcInfo gcInfo;
|
||||
private final CompositeData cdata;
|
||||
|
||||
/**
|
||||
* Notification type denoting that
|
||||
* the Java virtual machine has completed a garbage collection cycle.
|
||||
* This notification is emitted by a {@link GarbageCollectorMXBean}.
|
||||
* The value of this notification type is
|
||||
* {@code com.sun.management.gc.notification}.
|
||||
*/
|
||||
public static final String GARBAGE_COLLECTION_NOTIFICATION =
|
||||
"com.sun.management.gc.notification";
|
||||
|
||||
/**
|
||||
* Constructs a {@code GarbageCollectionNotificationInfo} object.
|
||||
*
|
||||
* @param gcName The name of the garbage collector used to perform the collection
|
||||
* @param gcAction The name of the action performed by the garbage collector
|
||||
* @param gcCause The cause the garbage collection action
|
||||
* @param gcInfo a GcInfo object providing statistics about the GC cycle
|
||||
*/
|
||||
public GarbageCollectionNotificationInfo(String gcName,
|
||||
String gcAction,
|
||||
String gcCause,
|
||||
GcInfo gcInfo) {
|
||||
if (gcName == null) {
|
||||
throw new NullPointerException("Null gcName");
|
||||
}
|
||||
if (gcAction == null) {
|
||||
throw new NullPointerException("Null gcAction");
|
||||
}
|
||||
if (gcCause == null) {
|
||||
throw new NullPointerException("Null gcCause");
|
||||
}
|
||||
this.gcName = gcName;
|
||||
this.gcAction = gcAction;
|
||||
this.gcCause = gcCause;
|
||||
this.gcInfo = gcInfo;
|
||||
this.cdata = new GarbageCollectionNotifInfoCompositeData(this);
|
||||
}
|
||||
|
||||
GarbageCollectionNotificationInfo(CompositeData cd) {
|
||||
GarbageCollectionNotifInfoCompositeData.validateCompositeData(cd);
|
||||
|
||||
this.gcName = GarbageCollectionNotifInfoCompositeData.getGcName(cd);
|
||||
this.gcAction = GarbageCollectionNotifInfoCompositeData.getGcAction(cd);
|
||||
this.gcCause = GarbageCollectionNotifInfoCompositeData.getGcCause(cd);
|
||||
this.gcInfo = GarbageCollectionNotifInfoCompositeData.getGcInfo(cd);
|
||||
this.cdata = cd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the garbage collector used to perform the collection
|
||||
*
|
||||
* @return the name of the garbage collector used to perform the collection
|
||||
*/
|
||||
public String getGcName() {
|
||||
return gcName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the action of the performed by the garbage collector
|
||||
*
|
||||
* @return the the action of the performed by the garbage collector
|
||||
*/
|
||||
public String getGcAction() {
|
||||
return gcAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cause the garbage collection
|
||||
*
|
||||
* @return the the cause the garbage collection
|
||||
*/
|
||||
public String getGcCause() {
|
||||
return gcCause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the GC information related to the last garbage collection
|
||||
*
|
||||
* @return the GC information related to the
|
||||
* last garbage collection
|
||||
*/
|
||||
public GcInfo getGcInfo() {
|
||||
return gcInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code GarbageCollectionNotificationInfo} object represented by the
|
||||
* given {@code CompositeData}.
|
||||
* The given {@code CompositeData} must contain
|
||||
* the following attributes:
|
||||
* <blockquote>
|
||||
* <table border>
|
||||
* <tr>
|
||||
* <th align=left>Attribute Name</th>
|
||||
* <th align=left>Type</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>gcName</td>
|
||||
* <td>{@code java.lang.String}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>gcAction</td>
|
||||
* <td>{@code java.lang.String}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>gcCause</td>
|
||||
* <td>{@code java.lang.String}</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>gcInfo</td>
|
||||
* <td>{@code javax.management.openmbean.CompositeData}</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* </blockquote>
|
||||
*
|
||||
* @param cd {@code CompositeData} representing a
|
||||
* {@code GarbageCollectionNotificationInfo}
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code cd} does not
|
||||
* represent a {@code GarbaageCollectionNotificationInfo} object.
|
||||
*
|
||||
* @return a {@code GarbageCollectionNotificationInfo} object represented
|
||||
* by {@code cd} if {@code cd} is not {@code null};
|
||||
* {@code null} otherwise.
|
||||
*/
|
||||
public static GarbageCollectionNotificationInfo from(CompositeData cd) {
|
||||
if (cd == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (cd instanceof GarbageCollectionNotifInfoCompositeData) {
|
||||
return ((GarbageCollectionNotifInfoCompositeData) cd).getGarbageCollectionNotifInfo();
|
||||
} else {
|
||||
return new GarbageCollectionNotificationInfo(cd);
|
||||
}
|
||||
}
|
||||
|
||||
public CompositeData toCompositeData(CompositeType ct) {
|
||||
return cdata;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.management;
|
||||
|
||||
import com.sun.management.GarbageCollectionNotificationInfo;
|
||||
import com.sun.management.GcInfo;
|
||||
import java.lang.reflect.Method;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.CompositeType;
|
||||
import javax.management.openmbean.CompositeDataSupport;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import javax.management.openmbean.OpenType;
|
||||
import javax.management.openmbean.SimpleType;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* A CompositeData for GarbageCollectionNotificationInfo for the local management support.
|
||||
* This class avoids the performance penalty paid to the
|
||||
* construction of a CompositeData use in the local case.
|
||||
*/
|
||||
public class GarbageCollectionNotifInfoCompositeData extends LazyCompositeData {
|
||||
private final GarbageCollectionNotificationInfo gcNotifInfo;
|
||||
|
||||
public GarbageCollectionNotifInfoCompositeData(GarbageCollectionNotificationInfo info) {
|
||||
this.gcNotifInfo = info;
|
||||
}
|
||||
|
||||
public GarbageCollectionNotificationInfo getGarbageCollectionNotifInfo() {
|
||||
return gcNotifInfo;
|
||||
}
|
||||
|
||||
public static CompositeData toCompositeData(GarbageCollectionNotificationInfo info) {
|
||||
GarbageCollectionNotifInfoCompositeData gcnicd =
|
||||
new GarbageCollectionNotifInfoCompositeData(info);
|
||||
return gcnicd.getCompositeData();
|
||||
}
|
||||
|
||||
private CompositeType getCompositeTypeByBuilder() {
|
||||
final GcInfoBuilder builder = AccessController.doPrivileged (new PrivilegedAction<GcInfoBuilder>() {
|
||||
public GcInfoBuilder run() {
|
||||
try {
|
||||
Class cl = Class.forName("com.sun.management.GcInfo");
|
||||
Field f = cl.getDeclaredField("builder");
|
||||
f.setAccessible(true);
|
||||
return (GcInfoBuilder)f.get(gcNotifInfo.getGcInfo());
|
||||
} catch(ClassNotFoundException e) {
|
||||
return null;
|
||||
} catch(NoSuchFieldException e) {
|
||||
return null;
|
||||
} catch(IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
CompositeType gict = null;
|
||||
synchronized(compositeTypeByBuilder) {
|
||||
gict = compositeTypeByBuilder.get(builder);
|
||||
if(gict == null) {
|
||||
OpenType[] gcNotifInfoItemTypes = new OpenType[] {
|
||||
SimpleType.STRING,
|
||||
SimpleType.STRING,
|
||||
SimpleType.STRING,
|
||||
builder.getGcInfoCompositeType(),
|
||||
};
|
||||
try {
|
||||
final String typeName =
|
||||
"sun.management.GarbageCollectionNotifInfoCompositeType";
|
||||
gict = new CompositeType(typeName,
|
||||
"CompositeType for GC notification info",
|
||||
gcNotifInfoItemNames,
|
||||
gcNotifInfoItemNames,
|
||||
gcNotifInfoItemTypes);
|
||||
compositeTypeByBuilder.put(builder,gict);
|
||||
} catch (OpenDataException e) {
|
||||
// shouldn't reach here
|
||||
throw Util.newException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return gict;
|
||||
}
|
||||
|
||||
protected CompositeData getCompositeData() {
|
||||
// CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH
|
||||
// gcNotifInfoItemNames!
|
||||
final Object[] gcNotifInfoItemValues;
|
||||
gcNotifInfoItemValues = new Object[] {
|
||||
gcNotifInfo.getGcName(),
|
||||
gcNotifInfo.getGcAction(),
|
||||
gcNotifInfo.getGcCause(),
|
||||
GcInfoCompositeData.toCompositeData(gcNotifInfo.getGcInfo())
|
||||
};
|
||||
|
||||
CompositeType gict = getCompositeTypeByBuilder();
|
||||
|
||||
try {
|
||||
return new CompositeDataSupport(gict,
|
||||
gcNotifInfoItemNames,
|
||||
gcNotifInfoItemValues);
|
||||
} catch (OpenDataException e) {
|
||||
// Should never reach here
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
// private static MappedMXBeanType gcInfoMapType;
|
||||
private static final String GC_NAME = "gcName";
|
||||
private static final String GC_ACTION = "gcAction";
|
||||
private static final String GC_CAUSE = "gcCause";
|
||||
private static final String GC_INFO = "gcInfo";
|
||||
private static final String[] gcNotifInfoItemNames = {
|
||||
GC_NAME,
|
||||
GC_ACTION,
|
||||
GC_CAUSE,
|
||||
GC_INFO
|
||||
};
|
||||
private static HashMap<GcInfoBuilder,CompositeType> compositeTypeByBuilder =
|
||||
new HashMap<GcInfoBuilder,CompositeType>();
|
||||
|
||||
public static String getGcName(CompositeData cd) {
|
||||
String gcname = getString(cd, GC_NAME);
|
||||
if (gcname == null) {
|
||||
throw new IllegalArgumentException("Invalid composite data: " +
|
||||
"Attribute " + GC_NAME + " has null value");
|
||||
}
|
||||
return gcname;
|
||||
}
|
||||
|
||||
public static String getGcAction(CompositeData cd) {
|
||||
String gcaction = getString(cd, GC_ACTION);
|
||||
if (gcaction == null) {
|
||||
throw new IllegalArgumentException("Invalid composite data: " +
|
||||
"Attribute " + GC_ACTION + " has null value");
|
||||
}
|
||||
return gcaction;
|
||||
}
|
||||
|
||||
public static String getGcCause(CompositeData cd) {
|
||||
String gccause = getString(cd, GC_CAUSE);
|
||||
if (gccause == null) {
|
||||
throw new IllegalArgumentException("Invalid composite data: " +
|
||||
"Attribute " + GC_CAUSE + " has null value");
|
||||
}
|
||||
return gccause;
|
||||
}
|
||||
|
||||
public static GcInfo getGcInfo(CompositeData cd) {
|
||||
CompositeData gcInfoData = (CompositeData) cd.get(GC_INFO);
|
||||
return GcInfo.from(gcInfoData);
|
||||
}
|
||||
|
||||
/** Validate if the input CompositeData has the expected
|
||||
* CompositeType (i.e. contain all attributes with expected
|
||||
* names and types).
|
||||
*/
|
||||
public static void validateCompositeData(CompositeData cd) {
|
||||
if (cd == null) {
|
||||
throw new NullPointerException("Null CompositeData");
|
||||
}
|
||||
|
||||
if (!isTypeMatched( getBaseGcNotifInfoCompositeType(), cd.getCompositeType())) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unexpected composite type for GarbageCollectionNotificationInfo");
|
||||
}
|
||||
}
|
||||
|
||||
// This is only used for validation.
|
||||
private static CompositeType baseGcNotifInfoCompositeType = null;
|
||||
private static synchronized CompositeType getBaseGcNotifInfoCompositeType() {
|
||||
if (baseGcNotifInfoCompositeType == null) {
|
||||
try {
|
||||
OpenType[] baseGcNotifInfoItemTypes = new OpenType[] {
|
||||
SimpleType.STRING,
|
||||
SimpleType.STRING,
|
||||
SimpleType.STRING,
|
||||
GcInfoCompositeData.getBaseGcInfoCompositeType()
|
||||
};
|
||||
baseGcNotifInfoCompositeType =
|
||||
new CompositeType("sun.management.BaseGarbageCollectionNotifInfoCompositeType",
|
||||
"CompositeType for Base GarbageCollectionNotificationInfo",
|
||||
gcNotifInfoItemNames,
|
||||
gcNotifInfoItemNames,
|
||||
baseGcNotifInfoItemTypes);
|
||||
} catch (OpenDataException e) {
|
||||
// shouldn't reach here
|
||||
throw Util.newException(e);
|
||||
}
|
||||
}
|
||||
return baseGcNotifInfoCompositeType;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -1805123446483771292L;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,6 +26,7 @@
|
||||
package sun.management;
|
||||
|
||||
import com.sun.management.GarbageCollectorMXBean;
|
||||
import com.sun.management.GarbageCollectionNotificationInfo;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryPoolMXBean;
|
||||
import java.lang.management.MemoryUsage;
|
||||
@ -35,9 +36,15 @@ import javax.management.openmbean.CompositeData;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implementation class for the garbage collector.
|
||||
@ -78,19 +85,111 @@ class GarbageCollectorImpl extends MemoryManagerImpl
|
||||
|
||||
// Sun JDK extension
|
||||
private GcInfoBuilder gcInfoBuilder;
|
||||
|
||||
private synchronized GcInfoBuilder getGcInfoBuilder() {
|
||||
if(gcInfoBuilder == null) {
|
||||
gcInfoBuilder = new GcInfoBuilder(this, getAllPoolNames());
|
||||
}
|
||||
return gcInfoBuilder;
|
||||
}
|
||||
|
||||
public GcInfo getLastGcInfo() {
|
||||
GcInfo info = getGcInfoBuilder().getLastGcInfo();
|
||||
return info;
|
||||
}
|
||||
|
||||
private final static String notifName =
|
||||
"javax.management.Notification";
|
||||
|
||||
private final static String[] gcNotifTypes = {
|
||||
GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION
|
||||
};
|
||||
|
||||
private MBeanNotificationInfo[] notifInfo = null;
|
||||
public MBeanNotificationInfo[] getNotificationInfo() {
|
||||
synchronized (this) {
|
||||
if (gcInfoBuilder == null) {
|
||||
gcInfoBuilder = new GcInfoBuilder(this, getAllPoolNames());
|
||||
if (notifInfo == null) {
|
||||
notifInfo = new MBeanNotificationInfo[1];
|
||||
notifInfo[0] = new MBeanNotificationInfo(gcNotifTypes,
|
||||
notifName,
|
||||
"GC Notification");
|
||||
}
|
||||
}
|
||||
return notifInfo;
|
||||
}
|
||||
|
||||
GcInfo info = gcInfoBuilder.getLastGcInfo();
|
||||
return info;
|
||||
private static long seqNumber = 0;
|
||||
private static long getNextSeqNumber() {
|
||||
return ++seqNumber;
|
||||
}
|
||||
|
||||
void createGCNotification(long timestamp,
|
||||
String gcName,
|
||||
String gcAction,
|
||||
String gcCause,
|
||||
GcInfo gcInfo) {
|
||||
|
||||
if (!hasListeners()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Notification notif = new Notification(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION,
|
||||
getObjectName(),
|
||||
getNextSeqNumber(),
|
||||
timestamp,
|
||||
gcName);
|
||||
GarbageCollectionNotificationInfo info =
|
||||
new GarbageCollectionNotificationInfo(gcName,
|
||||
gcAction,
|
||||
gcCause,
|
||||
gcInfo);
|
||||
|
||||
CompositeData cd =
|
||||
GarbageCollectionNotifInfoCompositeData.toCompositeData(info);
|
||||
notif.setUserData(cd);
|
||||
sendNotification(notif);
|
||||
}
|
||||
|
||||
public synchronized void addNotificationListener(NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
{
|
||||
boolean before = hasListeners();
|
||||
super.addNotificationListener(listener, filter, handback);
|
||||
boolean after = hasListeners();
|
||||
if (!before && after) {
|
||||
setNotificationEnabled(this, true);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removeNotificationListener(NotificationListener listener)
|
||||
throws ListenerNotFoundException {
|
||||
boolean before = hasListeners();
|
||||
super.removeNotificationListener(listener);
|
||||
boolean after = hasListeners();
|
||||
if (before && !after) {
|
||||
setNotificationEnabled(this,false);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removeNotificationListener(NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
Object handback)
|
||||
throws ListenerNotFoundException
|
||||
{
|
||||
boolean before = hasListeners();
|
||||
super.removeNotificationListener(listener,filter,handback);
|
||||
boolean after = hasListeners();
|
||||
if (before && !after) {
|
||||
setNotificationEnabled(this,false);
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectName getObjectName() {
|
||||
return Util.newObjectName(ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE, getName());
|
||||
}
|
||||
|
||||
native void setNotificationEnabled(GarbageCollectorMXBean gc,
|
||||
boolean enabled);
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,6 +27,7 @@ package sun.management;
|
||||
|
||||
import java.lang.management.MemoryUsage;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
@ -41,6 +42,9 @@ import javax.management.openmbean.SimpleType;
|
||||
import javax.management.openmbean.OpenType;
|
||||
import javax.management.openmbean.OpenDataException;
|
||||
import com.sun.management.GcInfo;
|
||||
import com.sun.management.GarbageCollectionNotificationInfo;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* A CompositeData for GcInfo for the local management support.
|
||||
@ -64,6 +68,44 @@ public class GcInfoCompositeData extends LazyCompositeData {
|
||||
return info;
|
||||
}
|
||||
|
||||
public static CompositeData toCompositeData(final GcInfo info) {
|
||||
final GcInfoBuilder builder = AccessController.doPrivileged (new PrivilegedAction<GcInfoBuilder>() {
|
||||
public GcInfoBuilder run() {
|
||||
try {
|
||||
Class cl = Class.forName("com.sun.management.GcInfo");
|
||||
Field f = cl.getDeclaredField("builder");
|
||||
f.setAccessible(true);
|
||||
return (GcInfoBuilder)f.get(info);
|
||||
} catch(ClassNotFoundException e) {
|
||||
return null;
|
||||
} catch(NoSuchFieldException e) {
|
||||
return null;
|
||||
} catch(IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
final Object[] extAttr = AccessController.doPrivileged (new PrivilegedAction<Object[]>() {
|
||||
public Object[] run() {
|
||||
try {
|
||||
Class cl = Class.forName("com.sun.management.GcInfo");
|
||||
Field f = cl.getDeclaredField("extAttributes");
|
||||
f.setAccessible(true);
|
||||
return (Object[])f.get(info);
|
||||
} catch(ClassNotFoundException e) {
|
||||
return null;
|
||||
} catch(NoSuchFieldException e) {
|
||||
return null;
|
||||
} catch(IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
GcInfoCompositeData gcicd =
|
||||
new GcInfoCompositeData(info,builder,extAttr);
|
||||
return gcicd.getCompositeData();
|
||||
}
|
||||
|
||||
protected CompositeData getCompositeData() {
|
||||
// CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH
|
||||
// baseGcInfoItemNames!
|
||||
@ -115,7 +157,6 @@ public class GcInfoCompositeData extends LazyCompositeData {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final String ID = "id";
|
||||
private static final String START_TIME = "startTime";
|
||||
private static final String END_TIME = "endTime";
|
||||
@ -231,7 +272,7 @@ public class GcInfoCompositeData extends LazyCompositeData {
|
||||
|
||||
// This is only used for validation.
|
||||
private static CompositeType baseGcInfoCompositeType = null;
|
||||
private static synchronized CompositeType getBaseGcInfoCompositeType() {
|
||||
static synchronized CompositeType getBaseGcInfoCompositeType() {
|
||||
if (baseGcInfoCompositeType == null) {
|
||||
try {
|
||||
baseGcInfoCompositeType =
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,6 +29,7 @@ import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryManagerMXBean;
|
||||
import java.lang.management.MemoryPoolMXBean;
|
||||
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
@ -38,7 +39,8 @@ import javax.management.ObjectName;
|
||||
* ManagementFactory.getMemoryManagerMXBeans() returns a list
|
||||
* of instances of this class.
|
||||
*/
|
||||
class MemoryManagerImpl implements MemoryManagerMXBean {
|
||||
class MemoryManagerImpl extends NotificationEmitterSupport
|
||||
implements MemoryManagerMXBean {
|
||||
|
||||
private final String name;
|
||||
private final boolean isValid;
|
||||
@ -76,6 +78,16 @@ class MemoryManagerImpl implements MemoryManagerMXBean {
|
||||
}
|
||||
private native MemoryPoolMXBean[] getMemoryPools0();
|
||||
|
||||
private MBeanNotificationInfo[] notifInfo = null;
|
||||
public MBeanNotificationInfo[] getNotificationInfo() {
|
||||
synchronized (this) {
|
||||
if(notifInfo == null) {
|
||||
notifInfo = new MBeanNotificationInfo[0];
|
||||
}
|
||||
}
|
||||
return notifInfo;
|
||||
}
|
||||
|
||||
public ObjectName getObjectName() {
|
||||
return Util.newObjectName(ManagementFactory.MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE, getName());
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ public interface VMManagement {
|
||||
public boolean isSynchronizerUsageSupported();
|
||||
public boolean isThreadAllocatedMemorySupported();
|
||||
public boolean isThreadAllocatedMemoryEnabled();
|
||||
public boolean isGcNotificationSupported();
|
||||
|
||||
// Class Loading Subsystem
|
||||
public long getTotalClassCount();
|
||||
|
@ -56,6 +56,8 @@ class VMManagementImpl implements VMManagement {
|
||||
private static boolean objectMonitorUsageSupport;
|
||||
private static boolean synchronizerUsageSupport;
|
||||
private static boolean threadAllocatedMemorySupport;
|
||||
private static boolean gcNotificationSupport;
|
||||
|
||||
|
||||
static {
|
||||
version = getVersion0();
|
||||
@ -100,6 +102,10 @@ class VMManagementImpl implements VMManagement {
|
||||
return threadAllocatedMemorySupport;
|
||||
}
|
||||
|
||||
public boolean isGcNotificationSupported() {
|
||||
return gcNotificationSupport;
|
||||
}
|
||||
|
||||
public native boolean isThreadContentionMonitoringEnabled();
|
||||
public native boolean isThreadCpuTimeEnabled();
|
||||
public native boolean isThreadAllocatedMemoryEnabled();
|
||||
|
@ -48,7 +48,7 @@ enum {
|
||||
JMM_VERSION_1_0 = 0x20010000,
|
||||
JMM_VERSION_1_1 = 0x20010100, // JDK 6
|
||||
JMM_VERSION_1_2 = 0x20010200, // JDK 7
|
||||
JMM_VERSION = 0x20010200
|
||||
JMM_VERSION = 0x20010201
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@ -293,6 +293,9 @@ typedef struct jmmInterface_1_ {
|
||||
jlongArray ids,
|
||||
jboolean lockedMonitors,
|
||||
jboolean lockedSynchronizers);
|
||||
void (JNICALL *SetGCNotificationEnabled) (JNIEnv *env,
|
||||
jobject mgr,
|
||||
jboolean enabled);
|
||||
} JmmInterface;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -36,3 +36,17 @@ JNIEXPORT jlong JNICALL Java_sun_management_GarbageCollectorImpl_getCollectionTi
|
||||
(JNIEnv *env, jobject mgr) {
|
||||
return jmm_interface->GetLongAttribute(env, mgr, JMM_GC_TIME_MS);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL Java_sun_management_GarbageCollectorImpl_setNotificationEnabled
|
||||
(JNIEnv *env, jobject dummy, jobject gc,jboolean enabled) {
|
||||
|
||||
if (gc == NULL) {
|
||||
JNU_ThrowNullPointerException(env, "Invalid GarbageCollectorMBean");
|
||||
return;
|
||||
}
|
||||
if((jmm_version > JMM_VERSION_1_2)
|
||||
|| (jmm_version == JMM_VERSION_1_2 && ((jmm_version&0xFF)>=1))) {
|
||||
jmm_interface->SetGCNotificationEnabled(env, gc, enabled);
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +95,13 @@ Java_sun_management_VMManagementImpl_initOptionalSupportFields
|
||||
|
||||
value = mos.isThreadAllocatedMemorySupported;
|
||||
setStaticBooleanField(env, cls, "threadAllocatedMemorySupport", value);
|
||||
|
||||
if ((jmm_version > JMM_VERSION_1_2) ||
|
||||
(jmm_version == JMM_VERSION_1_2 && ((jmm_version&0xFF) >= 1))) {
|
||||
setStaticBooleanField(env, cls, "gcNotificationSupport", JNI_TRUE);
|
||||
} else {
|
||||
setStaticBooleanField(env, cls, "gcNotificationSupport", JNI_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
|
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7036199
|
||||
* @summary Check that GarbageCollectionNotification contents are reasonable
|
||||
* @author Frederic Parain
|
||||
* @run main/othervm GarbageCollectionNotificationContentTest
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.lang.management.*;
|
||||
import java.lang.reflect.*;
|
||||
import javax.management.*;
|
||||
import javax.management.openmbean.*;
|
||||
import com.sun.management.GarbageCollectionNotificationInfo;
|
||||
import com.sun.management.GcInfo;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class GarbageCollectionNotificationContentTest {
|
||||
private static HashMap<String,GarbageCollectionNotificationInfo> listenerInvoked
|
||||
= new HashMap<String,GarbageCollectionNotificationInfo>();
|
||||
static volatile long count = 0;
|
||||
static volatile long number = 0;
|
||||
static Object synchronizer = new Object();
|
||||
|
||||
static class GcListener implements NotificationListener {
|
||||
public void handleNotification(Notification notif, Object handback) {
|
||||
String type = notif.getType();
|
||||
if (type.equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {
|
||||
GarbageCollectionNotificationInfo gcNotif =
|
||||
GarbageCollectionNotificationInfo.from((CompositeData) notif.getUserData());
|
||||
String source = ((ObjectName)notif.getSource()).getCanonicalName();
|
||||
synchronized(synchronizer) {
|
||||
if(listenerInvoked.get(source) == null) {
|
||||
listenerInvoked.put(((ObjectName)notif.getSource()).getCanonicalName(),gcNotif);
|
||||
count++;
|
||||
if(count >= number) {
|
||||
synchronizer.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
||||
final Boolean isNotificationSupported = AccessController.doPrivileged (new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
try {
|
||||
Class cl = Class.forName("sun.management.VMManagementImpl");
|
||||
Field f = cl.getDeclaredField("gcNotificationSupport");
|
||||
f.setAccessible(true);
|
||||
return f.getBoolean(null);
|
||||
} catch(ClassNotFoundException e) {
|
||||
return false;
|
||||
} catch(NoSuchFieldException e) {
|
||||
return false;
|
||||
} catch(IllegalAccessException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
if(!isNotificationSupported) {
|
||||
System.out.println("GC Notification not supported by the JVM, test skipped");
|
||||
return;
|
||||
}
|
||||
final ObjectName gcMXBeanPattern =
|
||||
new ObjectName("java.lang:type=GarbageCollector,*");
|
||||
Set<ObjectName> names =
|
||||
mbs.queryNames(gcMXBeanPattern, null);
|
||||
if (names.isEmpty())
|
||||
throw new Exception("Test incorrect: no GC MXBeans");
|
||||
number = names.size();
|
||||
for (ObjectName n : names) {
|
||||
if(mbs.isInstanceOf(n,"javax.management.NotificationEmitter")) {
|
||||
listenerInvoked.put(n.getCanonicalName(),null);
|
||||
GcListener listener = new GcListener();
|
||||
mbs.addNotificationListener(n, listener, null, null);
|
||||
}
|
||||
}
|
||||
// Invocation of System.gc() to trigger major GC
|
||||
System.gc();
|
||||
// Allocation of many short living and small objects to trigger minor GC
|
||||
Object data[] = new Object[32];
|
||||
for(int i = 0; i<100000000; i++) {
|
||||
data[i%32] = new int[8];
|
||||
}
|
||||
int wakeup = 0;
|
||||
synchronized(synchronizer) {
|
||||
while(count != number) {
|
||||
synchronizer.wait(10000);
|
||||
wakeup++;
|
||||
if(wakeup > 10)
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (GarbageCollectionNotificationInfo notif : listenerInvoked.values() ) {
|
||||
checkGarbageCollectionNotificationInfoContent(notif);
|
||||
}
|
||||
System.out.println("Test passed");
|
||||
}
|
||||
|
||||
private static void checkGarbageCollectionNotificationInfoContent(GarbageCollectionNotificationInfo notif) throws Exception {
|
||||
System.out.println("GC notification for "+notif.getGcName());
|
||||
System.out.print("Action: "+notif.getGcAction());
|
||||
System.out.println(" Cause: "+notif.getGcCause());
|
||||
GcInfo info = notif.getGcInfo();
|
||||
System.out.print("GC Info #" + info.getId());
|
||||
System.out.print(" start:" + info.getStartTime());
|
||||
System.out.print(" end:" + info.getEndTime());
|
||||
System.out.println(" (" + info.getDuration() + "ms)");
|
||||
Map<String, MemoryUsage> usage = info.getMemoryUsageBeforeGc();
|
||||
|
||||
List<String> pnames = new ArrayList<String>();
|
||||
for (Map.Entry entry : usage.entrySet() ) {
|
||||
String poolname = (String) entry.getKey();
|
||||
pnames.add(poolname);
|
||||
MemoryUsage busage = (MemoryUsage) entry.getValue();
|
||||
MemoryUsage ausage = (MemoryUsage) info.getMemoryUsageAfterGc().get(poolname);
|
||||
if (ausage == null) {
|
||||
throw new RuntimeException("After Gc Memory does not exist" +
|
||||
" for " + poolname);
|
||||
}
|
||||
System.out.println("Usage for pool " + poolname);
|
||||
System.out.println(" Before GC: " + busage);
|
||||
System.out.println(" After GC: " + ausage);
|
||||
}
|
||||
|
||||
// check if memory usage for all memory pools are returned
|
||||
List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
|
||||
for (MemoryPoolMXBean p : pools ) {
|
||||
if (!pnames.contains(p.getName())) {
|
||||
throw new RuntimeException("GcInfo does not contain " +
|
||||
"memory usage for pool " + p.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7036199
|
||||
* @summary Check that GarbageCollection notification are thrown by every GarbageCollectorMXBean
|
||||
* @author Frederic Parain
|
||||
* @run main/othervm GarbageCollectionNotificationTest
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.lang.management.*;
|
||||
import java.lang.reflect.*;
|
||||
import javax.management.*;
|
||||
import javax.management.openmbean.*;
|
||||
import com.sun.management.GarbageCollectionNotificationInfo;
|
||||
import com.sun.management.GcInfo;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class GarbageCollectionNotificationTest {
|
||||
private static HashMap<String,Boolean> listenerInvoked = new HashMap<String,Boolean>();
|
||||
static volatile long count = 0;
|
||||
static volatile long number = 0;
|
||||
static Object synchronizer = new Object();
|
||||
|
||||
static class GcListener implements NotificationListener {
|
||||
public void handleNotification(Notification notif, Object handback) {
|
||||
String type = notif.getType();
|
||||
if (type.equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {
|
||||
GarbageCollectionNotificationInfo gcNotif =
|
||||
GarbageCollectionNotificationInfo.from((CompositeData) notif.getUserData());
|
||||
String source = ((ObjectName)notif.getSource()).getCanonicalName();
|
||||
synchronized(synchronizer) {
|
||||
if(!listenerInvoked.get(source)) {
|
||||
listenerInvoked.put(((ObjectName)notif.getSource()).getCanonicalName(),true);
|
||||
count++;
|
||||
if(count >= number) {
|
||||
synchronizer.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
||||
final Boolean isNotificationSupported = AccessController.doPrivileged (new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
try {
|
||||
Class cl = Class.forName("sun.management.VMManagementImpl");
|
||||
Field f = cl.getDeclaredField("gcNotificationSupport");
|
||||
f.setAccessible(true);
|
||||
return f.getBoolean(null);
|
||||
} catch(ClassNotFoundException e) {
|
||||
return false;
|
||||
} catch(NoSuchFieldException e) {
|
||||
return false;
|
||||
} catch(IllegalAccessException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
if(!isNotificationSupported) {
|
||||
System.out.println("GC Notification not supported by the JVM, test skipped");
|
||||
return;
|
||||
}
|
||||
final ObjectName gcMXBeanPattern =
|
||||
new ObjectName("java.lang:type=GarbageCollector,*");
|
||||
Set<ObjectName> names =
|
||||
mbs.queryNames(gcMXBeanPattern, null);
|
||||
if (names.isEmpty())
|
||||
throw new Exception("Test incorrect: no GC MXBeans");
|
||||
number = names.size();
|
||||
for (ObjectName n : names) {
|
||||
if(mbs.isInstanceOf(n,"javax.management.NotificationEmitter")) {
|
||||
listenerInvoked.put(n.getCanonicalName(),false);
|
||||
GcListener listener = new GcListener();
|
||||
mbs.addNotificationListener(n, listener, null, null);
|
||||
}
|
||||
}
|
||||
// Invocation of System.gc() to trigger major GC
|
||||
System.gc();
|
||||
// Allocation of many short living and small objects to trigger minor GC
|
||||
Object data[] = new Object[32];
|
||||
for(int i = 0; i<100000000; i++) {
|
||||
data[i%32] = new int[8];
|
||||
}
|
||||
int wakeup = 0;
|
||||
synchronized(synchronizer) {
|
||||
while(count != number) {
|
||||
synchronizer.wait(10000);
|
||||
wakeup++;
|
||||
if(wakeup > 10)
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (String source : listenerInvoked.keySet()) {
|
||||
if(!listenerInvoked.get(source))
|
||||
throw new Exception("Test incorrect: notifications have not been sent for "
|
||||
+ source);
|
||||
}
|
||||
System.out.println("Test passed");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user