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 + -
显示快捷键?