garbagecollectionservice.java
来自「OpenJMS是一个开源的Java Message Service API 1.」· Java 代码 · 共 397 行
JAVA
397 行
/** * Redistribution and use of this software and associated documentation * ("Software"), with or without modification, are permitted provided * that the following conditions are met: * * 1. Redistributions of source code must retain copyright * statements and notices. Redistributions must also contain a * copy of this document. * * 2. Redistributions in binary form must reproduce the * above copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. The name "Exolab" must not be used to endorse or promote * products derived from this Software without prior written * permission of Exoffice Technologies. For written permission, * please contact info@exolab.org. * * 4. Products derived from this Software may not be called "Exolab" * nor may "Exolab" appear in their names without prior written * permission of Exoffice Technologies. Exolab is a registered * trademark of Exoffice Technologies. * * 5. Due credit should be given to the Exolab Project * (http://www.exolab.org/). * * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Copyright 2001-2004 (C) Exoffice Technologies Inc. All Rights Reserved. * * $Id: GarbageCollectionService.java,v 1.2 2005/08/30 05:09:45 tanderson Exp $ */package org.exolab.jms.gc;import java.util.LinkedList;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.exolab.jms.config.Configuration;import org.exolab.jms.config.GarbageCollectionConfiguration;import org.exolab.jms.events.BasicEventManager;import org.exolab.jms.events.Event;import org.exolab.jms.events.EventHandler;import org.exolab.jms.events.IllegalEventDefinedException;import org.exolab.jms.events.EventManager;import org.exolab.jms.service.Service;import org.exolab.jms.service.ServiceException;/** * The garbage collection service is responsible for managing all transient * garbage collection for OpenJMS, which includes messages, destinations, * endpoints etc. It does not deal with persistent data, which is handled * through the database service. Other services or managers can register * themselves with GarbageCollectionService if they implement the {@link * GarbageCollectable} interface. * <p/> * Gargabe collection will be initiated when the amount of free memory falls * below a low water mark, which is calculated as a percentage of total memory. * By default garbage collection will run when free memory falls below 20% of * total memory, this can be changed through the configuration file. * <p/> * The service will check the memory usage every 30 seconds by default. but this * can also be modified through the configuration file. * <p/> * In addition the garbage collection service can also be configured to execute * at regular intervals regardless the amount of residual free memory. This * option can be employed to ease the burden of performing wholesale garbage * collection when memory falls below the low water mark threshold. The default * value for this is 300 seconds. Setting this value to 0 will disable this * capability. * <p/> * This service makes use of the {@link BasicEventManager} to register events * for garbage collection. * * @author <a href="mailto:jima@intalio.com">Jim Alateras</a> * @version $Revision: 1.2 $ $Date: 2005/08/30 05:09:45 $ */public class GarbageCollectionService extends Service implements EventHandler { /** * This is the value of the transient garbage collection event that is used * to register with the {@link BasicEventManager}. When this event is * received the memory utilization is checked to determine whether we need * to perform some garbage collection. */ private final static int CHECK_FREE_MEMORY_EVENT = 1; /** * This event is used to unconditionally trigger garbage collection. */ private final static int GARBAGE_COLLECT_EVENT = 2; /** * The default low water threshold value before GC is initiated. This is * specified as a percentage with valid values ranging from 10-50. */ private int _gcLowWaterThreshold = 20; /** * The default interval, in seconds, that memory is checked for the low * water threshold. The default is 30 seconds. */ private int _memoryCheckInterval = 30 * 1000; /** * The default interval, in seconds, between successive executions of the * garbage collector. This will execute regardless the amount of free memory * left in the VM. */ private int _gcInterval = 300 * 1000; /** * This is the priority of that the GC thread uses to collect garbage. * Changing it effects how aggressive GC is performed. The default value is * 5. */ private int _gcThreadPriority = 5; /** * This is used to serialize access to the _collectingGarbage flag */ private final Object _gcGuard = new Object(); /** * This flag indicates whether garabage collection is in progress */ private boolean _collectingGarbage = false; /** * Maintains a list of all GarbageCollectable instances */ private LinkedList _gcList = new LinkedList(); /** * The event manager. */ private final EventManager _eventMgr; /** * The logger. */ private static final Log _log = LogFactory.getLog(GarbageCollectionService.class); /** * Create an instance of a garbage collection service. It uses the * configuration manager to extract the service parameters. * * @param config the configuration to use * @param eventMgr the event manager */ public GarbageCollectionService(Configuration config, EventManager eventMgr) { super("GarbageCollectionService"); if (config == null) { throw new IllegalArgumentException("Argument 'config' is null"); } if (eventMgr == null) { throw new IllegalArgumentException("Argument 'eventMgr' is null"); } GarbageCollectionConfiguration gcConfig = config.getGarbageCollectionConfiguration(); // read the value and ensure that it is within // the specified limits int low = gcConfig.getLowWaterThreshold(); if (low < 10) { low = 10; } if (low > 50) { low = 50; } _gcLowWaterThreshold = low; // read the memory check interval and fix it if it falls // outside the constraints int mem_interval = gcConfig.getMemoryCheckInterval(); if ((mem_interval > 0) && (mem_interval < 5)) { mem_interval = 5; } _memoryCheckInterval = mem_interval * 1000; // read the gc interval, which is optional int gc_interval = gcConfig.getGarbageCollectionInterval(); if (gc_interval <= 0) { gc_interval = 0; } _gcInterval = gc_interval * 1000; // read the gc thread priority int gc_priority = gcConfig.getGarbageCollectionThreadPriority(); if (gc_priority < Thread.MIN_PRIORITY) { gc_priority = Thread.MIN_PRIORITY; } if (gc_priority > Thread.MAX_PRIORITY) { gc_priority = Thread.MAX_PRIORITY; } _gcThreadPriority = gc_priority; _eventMgr = eventMgr; } /** * Check whether the low water threshold has been reached. * * @return boolean - true if it has; false otherwise */ public boolean belowLowWaterThreshold() { boolean result = false; long threshold = (long) ((Runtime.getRuntime().totalMemory() / 100) * _gcLowWaterThreshold); long free = Runtime.getRuntime().freeMemory(); if (_log.isDebugEnabled()) { _log.debug("GC Threshold=" + threshold + " Free=" + free); } if (threshold > free) { result = true; } return result; } /** * Register an entity that wishes to participate in the garbage collection * process. This entity will be added to the list of other registered * entities and will be called when GC is triggered. * * @param entry the entry to add to list */ public void register(GarbageCollectable entry) { if (entry != null) { synchronized (_gcList) { _gcList.add(entry); } } } /** * Unregister the specified entry from the list of garbge collectable * entities * * @param entry - entry to remove */ public void unregister(GarbageCollectable entry) { if (entry != null) { synchronized (_gcList) { _gcList.remove(entry); } } } public void doStart() throws ServiceException { // register an event with the event manager if (_memoryCheckInterval > 0) { _log.info("Registering Garbage Collection every " + _memoryCheckInterval + " for memory."); registerEvent(CHECK_FREE_MEMORY_EVENT, _memoryCheckInterval); } // optionally start garbage collection if (_gcInterval > 0) { _log.info("Registering Garbage Collection every " + _gcInterval + " for other resources."); registerEvent(GARBAGE_COLLECT_EVENT, _gcInterval); } } // implementation of EventHandler.handleEvent public void handleEvent(int event, Object callback, long time) { boolean valid_event = false; try { if (event == CHECK_FREE_MEMORY_EVENT) { valid_event = true; try { // collect garbage only below threshold if (belowLowWaterThreshold()) { _log.info("GC Collecting Garbage Free Heap below " + _gcLowWaterThreshold); collectGarbage(true); } } catch (Exception exception) { _log.error("Error in GC Service [CHECK_FREE_MEMORY_EVENT]", exception); } } else if (event == GARBAGE_COLLECT_EVENT) { valid_event = true; try { // collect garbage now collectGarbage(false); } catch (Exception exception) { _log.error("Error in GC Service [GARBAGE_COLLECT_EVENT]", exception); } } } finally { if (valid_event) { try { registerEvent(event, ((Long) callback).longValue()); } catch (Exception exception) { _log.error("Error in GC Service", exception); } } } } /** * Iterate through the list of registered {@link GarbageCollectable}s and * call collectGarbage on all of them. * * @param aggressive - true ofr aggressive garbage collection */ private void collectGarbage(boolean aggressive) { synchronized (_gcGuard) { if (_collectingGarbage) { // if we are in the middle of collecting garbage then // we can ignore this request safely. return; } else { _collectingGarbage = true; } } // if we get this far then we are the only thread that will // trigger garbage collection. First we must set the priority // of this thread int oldPriority = Thread.currentThread().getPriority(); try { Thread.currentThread().setPriority(_gcThreadPriority); Object[] list = _gcList.toArray(); for (int index = 0; index < list.length; index++) { try { GarbageCollectable collectable = (GarbageCollectable) list[index]; collectable.collectGarbage(aggressive); } catch (Exception exception) { _log.error("Error while collecting garbage", exception); } } } finally { Thread.currentThread().setPriority(oldPriority); } // we have finished collecting garbage synchronized (_gcGuard) { _collectingGarbage = false; } } /** * Register the specified event with the corresponding time with the {@link * BasicEventManager}. It will throw an exception if it cannot contact the * event manager or register the event. * * @param event the event to register * @param time the associated time * @throws GarbageCollectionServiceException * */ private void registerEvent(int event, long time) throws GarbageCollectionServiceException { try { _eventMgr.registerEventRelative( new Event(event, this, new Long(time)), time); } catch (IllegalEventDefinedException exception) { // rethrow as a more relevant exception throw new GarbageCollectionServiceException( "Failed to register event " + exception); } }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?