001 /* 002 // $Id: //open/mondrian/src/main/mondrian/util/NotificationMemoryMonitor.java#5 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2007-2007 Julian Hyde and others 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.util; 011 012 import java.lang.management.MemoryMXBean; 013 import java.lang.management.MemoryNotificationInfo; 014 import java.lang.management.MemoryUsage; 015 import java.lang.management.ManagementFactory; 016 import java.lang.management.MemoryPoolMXBean; 017 import java.lang.management.MemoryType; 018 import javax.management.Notification; 019 import javax.management.NotificationEmitter; 020 import javax.management.NotificationListener; 021 import org.apache.log4j.Logger; 022 023 /** 024 * The <code>NotificationMemoryMonitor</code> class uses the Java5 025 * memory management system to detect system low memory events. 026 * <p> 027 * This code is loosely based on the code taken from The Java 028 * Specialists' Newsletter, 029 * <a href="http://www.javaspecialists.co.za/archive/newsletter.do?issue=092" 030 * >issue 92</a> authored by Dr. Heinz M. Kabutz. 031 * As a note, his on-line newletters are a good source of Java information, 032 * take a look. 033 * <p> 034 * For more information one should review the Java5 classes in 035 * java.lang.management. 036 * 037 * 038 * @author <a>Richard M. Emberson</a> 039 * @since Feb 03 2007 040 * @version $Id: //open/mondrian/src/main/mondrian/util/NotificationMemoryMonitor.java#5 $ 041 */ 042 public class NotificationMemoryMonitor extends AbstractMemoryMonitor { 043 private static final Logger LOGGER = 044 Logger.getLogger(NotificationMemoryMonitor.class); 045 046 047 protected static final MemoryPoolMXBean TENURED_POOL; 048 049 static { 050 TENURED_POOL = findTenuredGenPool(); 051 } 052 053 private static MemoryPoolMXBean findTenuredGenPool() { 054 for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { 055 // I don't know whether this approach is better, or whether 056 // we should rather check for the pool name "Tenured Gen"? 057 if (pool.getType() == MemoryType.HEAP && 058 pool.isUsageThresholdSupported()) { 059 return pool; 060 } 061 } 062 throw new AssertionError("Could not find tenured space"); 063 } 064 065 /** 066 * The <code>NotificationHandler</code> implements the Java memory 067 * notification listener, <code>NotificationListener</code>, 068 * and is used to take notifications from Java and pass them on 069 * to the <code>NotificationMemoryMonitor</code>'s 070 * <code>Listerner</code>s. 071 */ 072 private class NotificationHandler implements NotificationListener { 073 074 /** 075 * This method is called by the Java5 code to notify clients 076 * registered with the JVM that the JVM memory threshold 077 * has been exceeded. 078 * 079 * @param notification 080 * @param unused 081 */ 082 public void handleNotification(final Notification notification, 083 final Object unused) { 084 final String type = notification.getType(); 085 086 if (type.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) { 087 final MemoryUsage usage = TENURED_POOL.getUsage(); 088 089 notifyListeners(usage.getUsed(), usage.getMax()); 090 } 091 } 092 } 093 094 095 /** 096 * Construct a <code>NotificationMemoryMonitor</code> instance and 097 * register it with the Java5 memory management system. 098 */ 099 NotificationMemoryMonitor() { 100 super(); 101 final MemoryMXBean mbean = ManagementFactory.getMemoryMXBean(); 102 final NotificationEmitter emitter = (NotificationEmitter) mbean; 103 104 // register with the Java5 memory management system. 105 emitter.addNotificationListener(new NotificationHandler(), null, null); 106 } 107 108 /** 109 * Get the <code>Logger</code>. 110 * 111 * @return the <code>Logger</code>. 112 */ 113 protected Logger getLogger() { 114 return LOGGER; 115 } 116 117 /** 118 * Notify the Java5 memory management system that there is a new 119 * low threshold. 120 * 121 * @param newLowThreshold the new threshold. 122 */ 123 protected void notifyNewLowThreshold(final long newLowThreshold) { 124 125 if (newLowThreshold == Long.MAX_VALUE) { 126 TENURED_POOL.setUsageThreshold(0); 127 } else { 128 TENURED_POOL.setUsageThreshold(newLowThreshold); 129 } 130 } 131 132 /** 133 * Get the maximum possible memory usage for this JVM instance. 134 * 135 * @return maximum memory that can be used. 136 */ 137 public long getMaxMemory() { 138 return TENURED_POOL.getUsage().getMax(); 139 } 140 /** 141 * Get the current memory usage for this JVM instance. 142 * 143 * @return current memory used. 144 */ 145 public long getUsedMemory() { 146 return TENURED_POOL.getUsage().getUsed(); 147 } 148 } 149 150 // End NotificationMemoryMonitor.java