/* * This software is subject to the terms of the Eclipse Public License v1.0 * Agreement, available at the following URL: * http://www.eclipse.org/legal/epl-v10.html. * You must accept the terms of that agreement to use this software. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package mondrian.util; import org.apache.log4j.Logger; import java.lang.management.*; import javax.management.*; /** * The <code>NotificationMemoryMonitor</code> class uses the Java5 * memory management system to detect system low memory events. * <p> * This code is loosely based on the code taken from The Java * Specialists' Newsletter, * <a href="http://www.javaspecialists.co.za/archive/newsletter.do?issue=092" * >issue 92</a> authored by Dr. Heinz M. Kabutz. * As a note, his on-line newletters are a good source of Java information, * take a look. * <p> * For more information one should review the Java5 classes in * java.lang.management. * * * @author <a>Richard M. Emberson</a> * @since Feb 03 2007 */ public class NotificationMemoryMonitor extends AbstractMemoryMonitor { private static final Logger LOGGER = Logger.getLogger(NotificationMemoryMonitor.class); protected static final MemoryPoolMXBean TENURED_POOL; static { TENURED_POOL = findTenuredGenPool(); } private static MemoryPoolMXBean findTenuredGenPool() { for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { // I don't know whether this approach is better, or whether // we should rather check for the pool name "Tenured Gen"? if (pool.getType() == MemoryType.HEAP && pool.isUsageThresholdSupported()) { return pool; } } throw new AssertionError("Could not find tenured space"); } /** * The <code>NotificationHandler</code> implements the Java memory * notification listener, <code>NotificationListener</code>, * and is used to take notifications from Java and pass them on * to the <code>NotificationMemoryMonitor</code>'s * <code>Listerner</code>s. */ private class NotificationHandler implements NotificationListener { /** * This method is called by the Java5 code to notify clients * registered with the JVM that the JVM memory threshold * has been exceeded. * * @param notification * @param unused */ public void handleNotification( final Notification notification, final Object unused) { final String type = notification.getType(); if (type.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) { final MemoryUsage usage = TENURED_POOL.getUsage(); notifyListeners(usage.getUsed(), usage.getMax()); } } } /** * Construct a <code>NotificationMemoryMonitor</code> instance and * register it with the Java5 memory management system. */ NotificationMemoryMonitor() { super(); final MemoryMXBean mbean = ManagementFactory.getMemoryMXBean(); final NotificationEmitter emitter = (NotificationEmitter) mbean; // register with the Java5 memory management system. emitter.addNotificationListener(new NotificationHandler(), null, null); } /** * Get the <code>Logger</code>. * * @return the <code>Logger</code>. */ protected Logger getLogger() { return LOGGER; } /** * Notify the Java5 memory management system that there is a new * low threshold. * * @param newLowThreshold the new threshold. */ protected void notifyNewLowThreshold(final long newLowThreshold) { if (newLowThreshold == Long.MAX_VALUE) { TENURED_POOL.setUsageThreshold(0); } else { TENURED_POOL.setUsageThreshold(newLowThreshold); } } /** * Get the maximum possible memory usage for this JVM instance. * * @return maximum memory that can be used. */ public long getMaxMemory() { return TENURED_POOL.getUsage().getMax(); } /** * Get the current memory usage for this JVM instance. * * @return current memory used. */ public long getUsedMemory() { return TENURED_POOL.getUsage().getUsed(); } } // End NotificationMemoryMonitor.java