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