1 19 20 package org.netbeans.modules.retouche.source.util; 21 22 import java.lang.management.ManagementFactory ; 23 import java.lang.management.MemoryMXBean ; 24 import java.lang.management.MemoryNotificationInfo ; 25 import java.lang.management.MemoryPoolMXBean ; 26 import java.lang.management.MemoryType ; 27 import java.lang.management.MemoryUsage ; 28 import java.util.ArrayList ; 29 import java.util.List ; 30 import javax.management.ListenerNotFoundException ; 31 import javax.management.Notification ; 32 import javax.management.NotificationEmitter ; 33 import javax.management.NotificationListener ; 34 import org.openide.ErrorManager; 35 36 45 public class LowMemoryNotifier { 46 47 private static final float DEFAULT_HEAP_LIMIT = 0.9f; 48 49 private static LowMemoryNotifier instance; 50 51 private final NotificationListener notificationListener = new Listener (); 52 private final List <LowMemoryListener> listeners; 53 private MemoryPoolMXBean pool; 54 private MemoryPoolMXBean cachedPool; private float heapLimit; 56 57 58 59 private LowMemoryNotifier() { 60 this.heapLimit = DEFAULT_HEAP_LIMIT; 61 this.listeners = new ArrayList <LowMemoryListener> (); 62 } 63 64 65 float getHeapLimit () { 66 return this.heapLimit; 67 } 68 69 void setHeapLimit (float heapLimit) { 70 this.heapLimit = heapLimit; 71 synchronized (this) { 72 if (this.pool != null) { 73 MemoryUsage mu = pool.getUsage(); 74 this.pool.setUsageThreshold ((long)(mu.getMax() * heapLimit)); 75 } 76 } 77 } 78 79 80 public synchronized void addLowMemoryListener (final LowMemoryListener listener) { 81 assert listener != null; 82 if (this.pool == null) { 83 this.pool = initJMX (); 84 } 85 assert this.pool != null; 86 final MemoryUsage usage = this.pool.getUsage(); 87 assert usage != null : String.format("Pool %s returned null MemoryUsage, Valid: %s\n",this.pool.getName(),this.pool.isValid() ? Boolean.TRUE : Boolean.FALSE); 88 if (usage != null && usage.getUsed() >= this.pool.getUsageThreshold()) { 89 listener.lowMemory (new LowMemoryEvent (this, this.pool)); 90 } 91 this.listeners.add (listener); 92 } 93 94 public synchronized void removeLowMemoryListener (final LowMemoryListener listener) { 95 assert listener != null; 96 this.listeners.remove (listener); 97 if (this.listeners.isEmpty() && this.pool != null) { 98 finishJMX (this.pool); 99 this.pool = null; 100 } 101 } 102 103 private void fireLowMemory () { 104 LowMemoryListener[] _listeners; 105 MemoryPoolMXBean _pool; 106 synchronized (this) { 107 _listeners = this.listeners.toArray(new LowMemoryListener[this.listeners.size()]); 108 _pool = this.pool; 109 } 110 if (_listeners.length > 0) { 111 assert _pool != null; 112 final LowMemoryEvent event = new LowMemoryEvent (this, _pool); 113 for (LowMemoryListener l : _listeners) { 114 l.lowMemory(event); 115 } 116 } 117 } 118 119 private MemoryPoolMXBean initJMX () { 120 List <MemoryPoolMXBean > pools = null; 121 if (this.cachedPool == null || !this.cachedPool.isValid()) { 122 pools = ManagementFactory.getMemoryPoolMXBeans(); 123 for (MemoryPoolMXBean pool : pools) { 124 if (pool.getType() == MemoryType.HEAP && pool.isUsageThresholdSupported()) { this.cachedPool = pool; 126 break; 127 } 128 } 129 } 130 assert this.cachedPool != null : dumpMemoryPoolMXBean (pools); 131 if (this.cachedPool != null) { 132 MemoryUsage mu = this.cachedPool.getUsage(); 133 this.cachedPool.setUsageThreshold((long)(mu.getMax() * heapLimit)); 134 MemoryMXBean mbean = ManagementFactory.getMemoryMXBean(); 135 ((NotificationEmitter )mbean).addNotificationListener(this.notificationListener,null,null); 136 } 137 return this.cachedPool; 138 } 139 140 private void finishJMX (final MemoryPoolMXBean pool) { 141 assert pool != null; 142 try { 143 MemoryMXBean mbean = ManagementFactory.getMemoryMXBean(); 144 ((NotificationEmitter )mbean).removeNotificationListener(this.notificationListener); 145 } catch (ListenerNotFoundException e) { 146 ErrorManager.getDefault().notify(e); 147 } 148 pool.setUsageThreshold(0); 149 } 150 151 private class Listener implements NotificationListener { 152 public void handleNotification(Notification notification, Object handback) { 153 final String notificationType = notification.getType(); 154 if (notificationType.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) { 155 fireLowMemory (); 156 } 157 } 158 159 } 160 161 private static String dumpMemoryPoolMXBean (List <MemoryPoolMXBean > pools) { 162 StringBuilder sb = new StringBuilder (); 163 for (MemoryPoolMXBean pool : pools) { 164 sb.append(String.format("Pool: %s Type: %s TresholdSupported: %s\n", pool.getName(), pool.getType(), pool.isUsageThresholdSupported() ? Boolean.TRUE : Boolean.FALSE)); 165 } 166 sb.append('\n'); 167 return sb.toString(); 168 } 169 170 public static synchronized LowMemoryNotifier getDefault () { 171 if (instance == null) { 172 instance = new LowMemoryNotifier (); 173 } 174 return instance; 175 } 176 177 } 178 | Popular Tags |