1 22 package org.jboss.monitor.services; 23 24 import org.jboss.system.ServiceMBeanSupport; 25 import org.jboss.util.Strings; 26 27 import javax.management.ObjectName ; 28 import javax.management.Notification ; 29 30 import org.jboss.monitor.alarm.Alarm; 31 import org.jboss.monitor.alarm.AlarmManager; 32 import org.jboss.monitor.alarm.MBeanImplAccess; 33 34 43 public class MemoryMonitor extends ServiceMBeanSupport 44 implements MemoryMonitorMBean 45 { 46 48 49 public static final String MEMORY_LOW = "jboss.alarm.memory.low"; 50 51 52 public static final String FREE_MEMORY_KEY = "freeMemory"; 53 54 55 public static final String DEFAULT_WARNING_THRESHOLD = "5m"; 56 57 58 public static final int DEFAULT_WARNING_MEASUREMENTS = 3; 59 60 61 public static final String DEFAULT_CRITICAL_THRESHOLD = "2m"; 62 63 64 public static final String DEFAULT_SAMPLING_PERIOD = "5sec"; 65 66 67 public static final long KILO = 1024; 68 public static final long MEGA = 1024 * 1024; 69 public static final long GIGA = 1024 * 1024 * 1024; 70 71 73 74 private long wThreshold; 75 76 77 private String wThresholdString; 78 79 80 private int wMeasurements; 81 82 83 private long cThreshold; 84 85 86 private String cThresholdString; 87 88 89 private long samplingPeriod; 90 91 92 private String samplingPeriodString; 93 94 95 private boolean isStopRequested; 96 97 98 private long freeMemory; 99 100 101 private int warningSamples; 102 103 104 AlarmManager alm = 105 new AlarmManager( 106 new MBeanImplAccess() { 107 public ObjectName getMBeanName() { return getServiceName(); } 108 public long getSequenceNumber() { return getNextNotificationSequenceNumber(); } 109 public void emitNotification(Notification n) { sendNotification(n); } 110 }); 111 112 114 117 public MemoryMonitor() 118 { 119 setFreeMemoryWarningThreshold(DEFAULT_WARNING_THRESHOLD); 121 setFreeMemoryCriticalThreshold(DEFAULT_CRITICAL_THRESHOLD); 122 setSamplingPeriod(DEFAULT_SAMPLING_PERIOD); 123 this.wMeasurements = DEFAULT_WARNING_MEASUREMENTS; 124 } 125 126 128 131 public void setTriggeringWarningMeasurements(int measurements) 132 { 133 if (measurements > 0) 134 { 135 this.wMeasurements = measurements; 136 } 137 } 138 139 142 public int getTriggeringWarningMeasurements() 143 { 144 return this.wMeasurements; 145 } 146 147 150 public void setFreeMemoryWarningThreshold(String s) 151 { 152 synchronized (this) 153 { 154 this.wThreshold = parseMemorySpec(s); 155 this.wThresholdString = s; 156 } 157 } 158 159 162 public String getFreeMemoryWarningThreshold() 163 { 164 return this.wThresholdString; 165 } 166 167 170 public void setFreeMemoryCriticalThreshold(String s) 171 { 172 synchronized (this) 173 { 174 this.cThreshold = parseMemorySpec(s); 175 this.cThresholdString = s; 176 } 177 } 178 179 182 public String getFreeMemoryCriticalThreshold() 183 { 184 return this.cThresholdString; 185 } 186 187 190 public void setSamplingPeriod(String s) 191 { 192 synchronized (this) 193 { 194 this.samplingPeriod = Strings.parsePositiveTimePeriod(s); 195 this.samplingPeriodString = s; 196 } 197 } 198 199 202 public String getSamplingPeriod() 203 { 204 return this.samplingPeriodString; 205 } 206 207 210 public long getFreeMemorySample() 211 { 212 synchronized (this) 213 { 214 return this.freeMemory; 215 } 216 } 217 218 221 public String getSeverity() 222 { 223 return alm.getSeverityAsString(MEMORY_LOW); 224 } 225 226 228 public void startService() throws Exception 229 { 230 Runnable r = new Runnable () 232 { 233 public void run() 234 { 235 log.debug("Started memory monitor thread" + 236 ", samplingPeriod=" + MemoryMonitor.this.samplingPeriodString + 237 ", warningThreshold=" + MemoryMonitor.this.wThresholdString + 238 ", criticalThreshold=" + MemoryMonitor.this.cThresholdString); 239 240 long wThreshold; 242 long cThreshold; 243 long samplingPeriod; 244 245 synchronized(MemoryMonitor.this) 246 { 247 wThreshold = MemoryMonitor.this.wThreshold; 248 cThreshold = MemoryMonitor.this.cThreshold; 249 samplingPeriod = MemoryMonitor.this.samplingPeriod; 250 } 251 252 warningSamples = wMeasurements; 254 255 while (!isStopRequested) 256 { 257 sampleMemory(wThreshold, cThreshold); 258 259 if (!isStopRequested) 260 { 261 try 262 { 263 Thread.sleep(samplingPeriod); 264 } 265 catch (InterruptedException e) 266 { 267 } 269 } 270 } 271 log.debug("Stopped memory monitor thread"); 272 } 273 }; 274 275 if (this.cThreshold > this.wThreshold) 277 { 278 throw new Exception ( 279 "FreeMemoryWarningThreshold (" + this.wThreshold + 280 ") set lower than FreeMemoryCriticalThreshold (" + this.cThreshold + ")"); 281 } 282 isStopRequested = false; 283 Thread t = new Thread (r, "Memory monitor thread of \"" + getServiceName() + "\""); 284 t.start(); 285 } 286 287 public void stopService() 288 { 289 this.isStopRequested = true; 291 } 292 293 295 298 private void sampleMemory(long wThreshold, long cThreshold) 299 { 300 long freeMemory = Runtime.getRuntime().freeMemory(); 301 302 synchronized (this) 303 { 304 this.freeMemory = freeMemory; 305 }; 306 307 if (freeMemory <= cThreshold) 308 { alm.setAlarm( 310 MEMORY_LOW, 311 Alarm.SEVERITY_CRITICAL, 312 "Free memory in critical state", 313 FREE_MEMORY_KEY, 314 new Long (freeMemory) 315 ); 316 warningSamples = wMeasurements; 318 } 319 else if (freeMemory <= wThreshold) 320 { 321 if (warningSamples > 0) 322 { 323 --warningSamples; 324 } 325 if (warningSamples == 0 326 || alm.getSeverity(MEMORY_LOW) == Alarm.SEVERITY_CRITICAL) 327 { 328 alm.setAlarm( 329 MEMORY_LOW, 330 Alarm.SEVERITY_WARNING, 331 "Free memory getting low", 332 FREE_MEMORY_KEY, 333 new Long (freeMemory) 334 ); 335 } 336 } 337 else 338 { 339 alm.setAlarm( 340 MEMORY_LOW, 341 Alarm.SEVERITY_NORMAL, 342 "Free memory at normal levels", 343 FREE_MEMORY_KEY, 344 new Long (freeMemory) 345 ); 346 warningSamples = wMeasurements; 348 } 349 } 350 351 362 private static long parseMemorySpec(String s) 363 { 364 try 365 { 366 int len = s.length(); 367 long factor = 0; 368 369 switch (s.charAt(len - 1)) 370 { 371 case 'k': 372 case 'K': 373 factor = KILO; 374 s = s.substring(0, len - 1); 375 break; 376 377 case 'm': 378 case 'M': 379 factor = MEGA; 380 s = s.substring(0, len - 1); 381 break; 382 383 case 'g': 384 case 'G': 385 factor = GIGA; 386 s = s.substring(0, len - 1); 387 break; 388 389 default: 390 factor = 1; 391 break; 392 } 393 long retval = Long.parseLong(s) * factor; 394 395 if (retval < 0) 396 { 397 throw new NumberFormatException (); 398 } 399 return retval; 400 } 401 catch (RuntimeException e) 402 { 403 throw new NumberFormatException ("Not a valid memory specification: " + s); 404 } 405 } 406 407 } 408 | Popular Tags |