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