Hi there, I've been following this thread with quite some interest. I like the idea of one monitoring thread that checks memory and then calls on the different stores to free some up if necessary. As an attachment I included a (very rough, first version, pre-alpha... you get it;-) StoreJanitor. To get this to run in your environment do the following: 1) add a new role named "janitor" to org/apache/cocoon/cocoon.roles 2) add an <janitor> element to cocoon.xconf, similar to the MRUMemoryStore ones 3) Expand the Store interface by a "public void free()" method. 4) Add the Store to the Janitor surveillance, i.e.: StoreJanitor janitor = (StoreJanitor)manager.lookup(StoreJanitor.ROLE); janitor.addToSurveillance(this); As mentioned above, this is far from complete. I'm sending this in so people that are more knowledgable than I am can take a look at it. I'd appreciate any (rocks!, sucks) feedback. Thanks, Christian On Wed, Aug 29, 2001 at 12:18:46AM +0200, Gerhard Froehlich wrote: > >> >Wow, where have you been before? :))) > Always there watching and learning much through this project and its > participants :). But most of the time in the dungeons of commercial > software development and its deadlines. > >> >Yes, you are right - that's not necessary and this might be the > >> >performance issue. > >> >Reducing checker threads amount down to one would decrease amount of > >> >runFinalization()/gc() > >> >calls in two times - giving better performance. > >> > > >> >Could we use just one static checker thread? > We have to test this. When static, we have namely one cleanup thread but > still two stores to free(). For the moment I don't know if this work. > But I have the strong feeling that it won't. Too bad that Carsten is > away for a couple of weeks. He would certainly have some good ideas for > the pipline configuration. But I will test this with a static thread. > >> >There is an issue with configuration though... Which > >configuration to use, > >> >from what store... > Maybe we can add a sample configuration to the cocoon.xconf according > to a reference config for the Xms Xmx parameters. Berin made some > good suggestions some threads below. I can add it to the cocoon.xconf. > >> How about a separate component to do the checking? > >(MRUMemoryStoreJanitor?) > >> Each MRUMemoryStore would register its requested heapsize & > >freememory with > >> the janitor, and it would be responsible for the worker thread. It would > > > >Good suggestion and I kind of like this name ;) > >Gerhard, what do you think? > Good suggestion. But I would name it StoreJanitor. Because the > MRUMemoryStore > is *only* a component. Maybe there will be a LRUMemoryStore or combination > of > both in nearer future :). Every store component implements the store > interface, so > the StoreJanitor would have access to the free() method of every store > component. > Then we would have a seperate cleanup component for every store > implementation. > I would implement the stores as singelton classes with one instance for > better > control about the memory. Because, how do you decide from which store > instance > to free memory. Maybe there is one with many small objects and another with > less > but huge objects. You can't determine, like in C, the byte size of each > object in java easy. > >> try to keep the JVM totalMemory below the sum of all the registered > >> heapsizes, and freeMemory below the sum of all registered freememories. > >Here I think that idea (originally) was that heapsize specifies > >heapsize of the JVM, > >but not the size of the store (because it is (almost) impossible > >to determine), so my > >understanding is that these parameters (heapsize and freememory) > >should also > >go into janitor configuration. > Yeah, thats right. But I had the opinion that there is only one store > instance. > (I tested it too carelessly :( ) > This gc()->jvm.FreeMemory()->gc()->jvm.FreeMemory() is the proposed > implementation (hack) from javasoft to determine memory consumption > of objects in java. > >> If runFinalization/gc isn't enough to create the free memory, a > >round-robin > >> approach (or other algorithm) could be used to select a > >MRUMemoryStore to > >> free an object from. > Yes, that would be a possible approach to decide from which store to free(). > But > I still don't understand why 2 or more stores? > >> Just my .02 :) > Mine too :) > > Cheers > Gerhard > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, email: [EMAIL PROTECTED] >
/***************************************************************************** * Copyright (C) The Apache Software Foundation. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package org.apache.cocoon.components.store; import org.apache.avalon.framework.component.Component; import org.apache.avalon.framework.configuration.Configurable; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.parameters.Parameters; import org.apache.avalon.framework.logger.AbstractLoggable; import org.apache.avalon.framework.thread.ThreadSafe; import java.util.List; import java.util.ArrayList; import java.util.Collections; import java.util.ListIterator; /** * This class monitors memory usage of thr JVM. * It calls the <code>free()</code> method in <code>Store</code>s * when memory gets low to free up some. * * @author <a href="mailto:[EMAIL PROTECTED]">Gerhard Froehlich</a> * @author <a href="mailto:[EMAIL PROTECTED]">Davanum Srinivas</a> * @author <a href="mailto:[EMAIL PROTECTED]">Christian Schmitt</a> * */ public class StoreJanitor extends AbstractLoggable implements Component, Configurable, Runnable, ThreadSafe { /** * The Avalon role name */ final static String ROLE = "org.apache.cocoon.components.store.StoreJanitor"; /** * Indicates how much memory should be left free in the JVM for * normal operation. */ private int freememory; /** * Indicates how big the heap size can grow to before the cleanup thread kicks in. * The default value is based on the default maximum heap size of 64Mb. */ private int heapsize; /** * Indicates the time in seconds to sleep between memory checks. */ private long cleanupthreadinterval; /** * Indicates the daemon thread priority. */ private int priority; /** * Store of stores */ private List stores = Collections.synchronizedList(new ArrayList()); /** * The Runtime */ private Runtime jvm; public void configure(Configuration config) throws ConfigurationException { getLogger().debug("About to be configured!"); Parameters params = Parameters.fromConfiguration(config); this.freememory = params.getParameterAsInteger("freememory", 1000000); this.heapsize = params.getParameterAsInteger("heapsize", 60000000); this.cleanupthreadinterval = params.getParameterAsInteger("cleanupthreadinterval", 10); this.priority = params.getParameterAsInteger("threadpriority",Thread.currentThread().getPriority()); if ((this.priority < 1) || (this.priority > 10)) { throw new ConfigurationException("StoreJanitor cleanup thread priority must be between 1 and 10!"); } if ((this.cleanupthreadinterval < 1)) { throw new ConfigurationException("StoreJanitor cleanup thread interval must be at least 1 second!"); } Thread janitor = new Thread(this); janitor.setDaemon(true); janitor.setPriority(this.priority); janitor.setName("janitor"); janitor.start(); } /** * The background thread that monitors memory. * If memory is getting low, appropriate actions have to be taken. */ public void run() { while(true) { if (memoryLow()) { ListIterator li = stores.listIterator(); while (li.hasNext()) { Store s = (Store)li.next(); getLogger().debug("Calling " + s.toString() + " to free some memory"); s.free(); } } try { Thread.currentThread().sleep(this.cleanupthreadinterval * 1000); } catch (InterruptedException ignore) {} } } /** * Add a Store to be watched. */ public void addToSurveillance(Store store) { stores.add(store); getLogger().debug(store.toString() + " added to surveillance"); } /** * Remove a Store from being watched. */ public void removeFromSurveillance(Store store) { stores.remove(store); getLogger().debug(store.toString() + " removed from surveillance"); } /** * Method to check if memory is running low in the jvm. */ private boolean memoryLow() { return jvm.totalMemory() > heapsize && jvm.freeMemory() < freememory; } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, email: [EMAIL PROTECTED]