1 45 package org.exolab.jms.gc; 46 47 import java.util.LinkedList ; 48 49 import org.apache.commons.logging.Log; 50 import org.apache.commons.logging.LogFactory; 51 52 import org.exolab.jms.config.Configuration; 53 import org.exolab.jms.config.ConfigurationManager; 54 import org.exolab.jms.config.GarbageCollectionConfiguration; 55 import org.exolab.jms.service.BasicService; 56 import org.exolab.jms.service.ServiceException; 57 import org.exolab.jms.service.ServiceState; 58 import org.exolab.jms.events.BasicEventManager; 59 import org.exolab.jms.events.Event; 60 import org.exolab.jms.events.EventHandler; 61 import org.exolab.jms.events.IllegalEventDefinedException; 62 63 64 93 public class GarbageCollectionService 94 extends BasicService 95 implements EventHandler { 96 97 100 private final static String GC_SERVICE_NAME = "GCCollectionService"; 101 102 108 private final static int CHECK_FREE_MEMORY_EVENT = 1; 109 110 113 private final static int GARBAGE_COLLECT_EVENT = 2; 114 115 118 private static GarbageCollectionService _instance = null; 119 120 123 private static final Object _creator = new Object (); 124 125 130 private int _gcLowWaterThreshold = 20; 131 132 136 private int _memoryCheckInterval = 30 * 1000; 137 138 143 private int _gcInterval = 300 * 1000; 144 145 150 private int _gcThreadPriority = 5; 151 152 155 private final Object _gcGuard = new Object (); 156 157 160 private boolean _collectingGarbage = false; 161 162 165 private LinkedList _gcList = new LinkedList (); 166 167 170 private static final Log _log = 171 LogFactory.getLog(GarbageCollectionService.class); 172 173 174 180 public static GarbageCollectionService instance() 181 throws GarbageCollectionServiceException { 182 if (_instance == null) { 183 synchronized (_creator) { 184 if (_instance == null) { 187 _instance = new GarbageCollectionService(); 188 } 189 } 190 } 191 192 return _instance; 193 } 194 195 201 GarbageCollectionService() { 202 super(GC_SERVICE_NAME); 203 204 Configuration config = ConfigurationManager.getConfig(); 206 GarbageCollectionConfiguration gc_config = 207 config.getGarbageCollectionConfiguration(); 208 209 int low = gc_config.getLowWaterThreshold(); 212 if (low < 10) { 213 low = 10; 214 } 215 216 if (low > 50) { 217 low = 50; 218 } 219 _gcLowWaterThreshold = low; 220 221 int mem_interval = gc_config.getMemoryCheckInterval(); 224 if ((mem_interval > 0) && 225 (mem_interval < 5)) { 226 mem_interval = 5; 227 } 228 _memoryCheckInterval = mem_interval * 1000; 229 230 int gc_interval = gc_config.getGarbageCollectionInterval(); 232 if (gc_interval <= 0) { 233 gc_interval = 0; 234 } 235 _gcInterval = gc_interval * 1000; 236 237 int gc_priority = gc_config.getGarbageCollectionThreadPriority(); 239 if (gc_priority < Thread.MIN_PRIORITY) { 240 gc_priority = Thread.MIN_PRIORITY; 241 } 242 243 if (gc_priority > Thread.MAX_PRIORITY) { 244 gc_priority = Thread.MAX_PRIORITY; 245 } 246 _gcThreadPriority = gc_priority; 247 } 248 249 254 public boolean belowLowWaterThreshold() { 255 boolean result = false; 256 long threshold = (long) ((Runtime.getRuntime().totalMemory() / 100) * 257 _gcLowWaterThreshold); 258 long free = Runtime.getRuntime().freeMemory(); 259 260 if (_log.isDebugEnabled()) { 261 _log.debug("GC Threshold=" + threshold + " Free=" + free); 262 } 263 if (threshold > free) { 264 result = true; 265 } 266 267 return result; 268 } 269 270 277 public void register(GarbageCollectable entry) { 278 if (entry != null) { 279 synchronized (_gcList) { 280 _gcList.add(entry); 281 } 282 } 283 } 284 285 291 public void unregister(GarbageCollectable entry) { 292 if (entry != null) { 293 synchronized (_gcList) { 294 _gcList.remove(entry); 295 } 296 } 297 } 298 299 public void run() { 301 } 303 304 public void start() 306 throws ServiceException { 307 308 if (_memoryCheckInterval > 0) { 310 _log.info("Registering Garbage Collection every " + 311 _memoryCheckInterval + " for memory."); 312 registerEvent(CHECK_FREE_MEMORY_EVENT, _memoryCheckInterval); 313 } 314 315 if (_gcInterval > 0) { 317 _log.info("Registering Garbage Collection every " + 318 _gcInterval + " for other resources."); 319 registerEvent(GARBAGE_COLLECT_EVENT, _gcInterval); 320 } 321 322 this.setState(ServiceState.RUNNING); 323 } 324 325 public void stop() 327 throws ServiceException { 328 329 this.setState(ServiceState.STOPPED); 330 } 331 332 public void handleEvent(int event, Object callback, long time) { 334 boolean valid_event = false; 335 336 try { 337 if (event == CHECK_FREE_MEMORY_EVENT) { 338 valid_event = true; 339 try { 340 if (belowLowWaterThreshold()) { 342 _log.info("GC Collecting Garbage Free Heap below " 343 + _gcLowWaterThreshold); 344 collectGarbage(true); 345 } 346 } catch (Exception exception) { 347 _log.error("Error in GC Service [CHECK_FREE_MEMORY_EVENT]", 348 exception); 349 } 350 } else if (event == GARBAGE_COLLECT_EVENT) { 351 valid_event = true; 352 try { 353 collectGarbage(false); 355 } catch (Exception exception) { 356 _log.error("Error in GC Service [GARBAGE_COLLECT_EVENT]", 357 exception); 358 } 359 } 360 } finally { 361 if (valid_event) { 362 try { 363 registerEvent(event, ((Long ) callback).longValue()); 364 } catch (Exception exception) { 365 _log.error("Error in GC Service", exception); 366 } 367 } 368 } 369 } 370 371 377 private void collectGarbage(boolean aggressive) { 378 synchronized (_gcGuard) { 379 if (_collectingGarbage) { 380 return; 383 } else { 384 _collectingGarbage = true; 385 } 386 } 387 388 int oldPriority = Thread.currentThread().getPriority(); 392 try { 393 Thread.currentThread().setPriority(_gcThreadPriority); 394 Object [] list = _gcList.toArray(); 395 for (int index = 0; index < list.length; index++) { 396 try { 397 GarbageCollectable collectable = 398 (GarbageCollectable) list[index]; 399 collectable.collectGarbage(aggressive); 400 } catch (Exception exception) { 401 _log.error("Error while collecting garbage", exception); 402 } 403 } 404 } finally { 405 Thread.currentThread().setPriority(oldPriority); 406 } 407 408 synchronized (_gcGuard) { 410 _collectingGarbage = false; 411 } 412 } 413 414 423 private void registerEvent(int event, long time) 424 throws GarbageCollectionServiceException { 425 try { 426 BasicEventManager.instance().registerEventRelative( 427 new Event(event, this, new Long (time)), time); 428 } catch (IllegalEventDefinedException exception) { 429 throw new GarbageCollectionServiceException( 431 "Failed to registerEvent " + exception); 432 } 433 } 434 435 } 436 | Popular Tags |