You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by po...@apache.org on 2004/12/28 02:39:23 UTC

cvs commit: jakarta-commons/jelly/src/java/org/apache/commons/jelly/util TagUtils.java

polx        2004/12/27 17:39:23

  Modified:    jelly/src/java/org/apache/commons/jelly/impl
                        StaticTagScript.java TagScript.java
               jelly/src/java/org/apache/commons/jelly JellyContext.java
               jelly/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml
                        TestParser.java
               jelly/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml
                        TransformTag.java
               jelly/src/java/org/apache/commons/jelly/util TagUtils.java
  Added:       jelly/src/test/org/apache/commons/jelly/core
                        TestCoreMemoryLeak.java BaseMemoryLeakTest.java
  Removed:     jelly/src/java/org/apache/commons/jelly/impl
                        WeakReferenceWrapperScript.java
  Log:
  Tag caching is now done in the JellyContext.
  The TestCoreMemoryLeak shows that, at least with some usage of JellyContext.clear(), one avoids leaks.
  Removing Tag-caching flag. Also, removing the WeakReferenceWrapperScript, both were in the era of ThreadLocal which is to be finished.
  
  Have tested these with an amount of the tag-libs... had to change the XML one but otherwise apparently none.
  
  Feedback and testing eagerly welcome!
  paul
  
  Revision  Changes    Path
  1.25      +2 -2      jakarta-commons/jelly/src/java/org/apache/commons/jelly/impl/StaticTagScript.java
  
  Index: StaticTagScript.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jelly/src/java/org/apache/commons/jelly/impl/StaticTagScript.java,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- StaticTagScript.java	16 Sep 2004 01:12:11 -0000	1.24
  +++ StaticTagScript.java	28 Dec 2004 01:39:22 -0000	1.25
  @@ -59,14 +59,14 @@
   
           Tag tag = null;
           try {
  -            tag = getTag();
  +            tag = getTag(context);
   
               // lets see if we have a dynamic tag
               if (tag instanceof StaticTag) {
                   tag = findDynamicTag(context, (StaticTag) tag);
               }
   
  -            setTag(tag);
  +            setTag(tag,context);
           } catch (JellyException e) {
               throw new JellyTagException(e);
           }
  
  
  
  1.47      +12 -31    jakarta-commons/jelly/src/java/org/apache/commons/jelly/impl/TagScript.java
  
  Index: TagScript.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jelly/src/java/org/apache/commons/jelly/impl/TagScript.java,v
  retrieving revision 1.46
  retrieving revision 1.47
  diff -u -r1.46 -r1.47
  --- TagScript.java	27 Oct 2004 21:50:53 -0000	1.46
  +++ TagScript.java	28 Dec 2004 01:39:22 -0000	1.47
  @@ -61,15 +61,6 @@
       /** The Log to which logging calls will be made. */
       private static final Log log = LogFactory.getLog(TagScript.class);
   
  -    /**
  -     * Thread local storage for the tag used by the current thread.
  -     * This allows us to pool tag instances, per thread to reduce object construction
  -     * over head, if we need it.
  -     *
  -     * Note that we could use the stack and create a new tag for each invocation
  -     * if we made a slight change to the Script API to pass in the parent tag.
  -     */
  -    private ThreadLocal tagHolder = new ThreadLocal();
   
       /** The attribute expressions that are created */
       protected Map attributes = new Hashtable();
  @@ -194,11 +185,8 @@
       public void run(JellyContext context, XMLOutput output) throws JellyTagException {
           URL rootURL = context.getRootURL();
           URL currentURL = context.getCurrentURL();
  -        if ( ! context.isCacheTags() ) {
  -            clearTag();
  -        }
           try {
  -            Tag tag = getTag();
  +            Tag tag = getTag(context);
               if ( tag == null ) {
                   return;
               }
  @@ -295,15 +283,15 @@
       /**
        * @return the tag to be evaluated, creating it lazily if required.
        */
  -    public Tag getTag() throws JellyException {
  -        Tag tag = (Tag) tagHolder.get();
  +    public Tag getTag(JellyContext context) throws JellyException {
  +        Tag tag = context.getTagOfTagScript(this);
           if ( tag == null ) {
               tag = createTag();
               if ( tag != null ) {
  -                tagHolder.set(tag);
  +                context.setTagForScript(this,tag);
               }
           }
  -        configureTag(tag);
  +        configureTag(tag,context);
           return tag;
       }
   
  @@ -494,21 +482,20 @@
           return null;
       }
   
  -
  +	
       /**
        * Compiles a newly created tag if required, sets its parent and body.
        */
  -    protected void configureTag(Tag tag) throws JellyException {
  +    protected void configureTag(Tag tag, JellyContext context) throws JellyException {
           if (tag instanceof CompilableTag) {
               ((CompilableTag) tag).compile();
           }
           Tag parentTag = null;
           if ( parent != null ) {
  -            parentTag = parent.getTag();
  +            parentTag = parent.getTag(context);
           }
           tag.setParent( parentTag );
  -        tag.setBody( new WeakReferenceWrapperScript(tagBody) );
  -        //tag.setBody( tagBody );
  +        tag.setBody( tagBody );
   
           if (tag instanceof NamespaceAwareTag) {
               NamespaceAwareTag naTag = (NamespaceAwareTag) tag;
  @@ -519,19 +506,13 @@
           }
       }
   
  -    /**
  -     * Flushes the current cached tag so that it will be created, lazily, next invocation
  -     */
  -    protected void clearTag() {
  -        tagHolder.set(null);
  -    }
   
       /**
        * Allows the script to set the tag instance to be used, such as in a StaticTagScript
        * when a StaticTag is switched with a DynamicTag
        */
  -    protected void setTag(Tag tag) {
  -        tagHolder.set(tag);
  +    protected void setTag(Tag tag, JellyContext context) {
  +        context.setTagForScript(this,tag);
       }
   
       /**
  
  
  
  1.62      +39 -27    jakarta-commons/jelly/src/java/org/apache/commons/jelly/JellyContext.java
  
  Index: JellyContext.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jelly/src/java/org/apache/commons/jelly/JellyContext.java,v
  retrieving revision 1.61
  retrieving revision 1.62
  diff -u -r1.61 -r1.62
  --- JellyContext.java	9 Sep 2004 15:10:03 -0000	1.61
  +++ JellyContext.java	28 Dec 2004 01:39:23 -0000	1.62
  @@ -25,6 +25,7 @@
   import java.util.Map;
   
   import org.apache.commons.jelly.parser.XMLParser;
  +import org.apache.commons.jelly.impl.TagScript;
   import org.apache.commons.jelly.util.ClassLoaderUtils;
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
  @@ -90,8 +91,15 @@
       /** Should we export tag libraries to our parents context */
       private boolean exportLibraries = true;
   
  -    /** Should we cache Tag instances, per thread, to reduce object contruction overhead? */
  -    private boolean cacheTags = false;
  +    /** A map that associates TagScript objects to Tag objects.
  +      * Is made a WeakHashMap so that the storage is discarded if the 
  +      * Script is discarded.
  +      */
  +    private Map tagHolderMap = new java.util.WeakHashMap(5);
  +    // THINKME: Script objects are like Object (for equals and hashCode) I think.
  +    //          It should be asy to optimize hash-map distribution, e.g. by
  +    //          shifting the hashcode return value (presuming Object.hashcode()
  +    //          is something like an address)
   
       /**
        * Create a new context with the currentURL set to the rootURL
  @@ -133,7 +141,6 @@
           this.rootURL = parent.rootURL;
           this.currentURL = parent.currentURL;
           this.variables.put("parentScope", parent.variables);
  -        this.cacheTags = parent.cacheTags;
           init();
       }
   
  @@ -377,7 +384,36 @@
       public JellyContext newJellyContext() {
           return createChildContext();
       }
  +    
   
  +    /** @return the tag associated to the given TagScript for the current run.
  +      */
  +    public Tag getTagOfTagScript(TagScript script) {
  +        if( script == null )
  +            return null;
  +        return (Tag) tagHolderMap.get(script);
  +    }
  +	
  +	/** @return the Map that associates the the Tags to Scripts */
  +	public Map getTagHolderMap() {
  +		return tagHolderMap;
  +	}
  +    
  +    /** Associates, for the run of this context, the tag of this TagScript.
  +      */
  +    public void setTagForScript(TagScript script, Tag tag) {
  +        tagHolderMap.put(script,tag);
  +    }
  +    
  +    /** Clears both the script-to-tags association and the variables association.
  +      */
  +    public void clear() {
  +        tagHolderMap.clear();
  +        variables.clear();
  +    }
  +    
  +    
  +    
       /** Registers the given tag library against the given namespace URI.
        * This should be called before the parser is used.
        */
  @@ -787,30 +823,6 @@
        */
       public void setCurrentURL(URL currentURL) {
           this.currentURL = currentURL;
  -    }
  -
  -    /**
  -     * Returns whether caching of Tag instances, per thread, is enabled.
  -     * Caching Tags can boost performance, on some JVMs, by reducing the cost of
  -     * object construction when running Jelly inside a multi-threaded application server
  -     * such as a Servlet engine.
  -     *
  -     * @return whether caching of Tag instances is enabled.
  -     */
  -    public boolean isCacheTags() {
  -        return cacheTags;
  -    }
  -
  -    /**
  -     * Sets whether caching of Tag instances, per thread, is enabled.
  -     * Caching Tags can boost performance, on some JVMs, by reducing the cost of
  -     * object construction when running Jelly inside a multi-threaded application server
  -     * such as a Servlet engine.
  -     *
  -     * @param cacheTags Whether caching should be enabled or disabled.
  -     */
  -    public void setCacheTags(boolean cacheTags) {
  -        this.cacheTags = cacheTags;
       }
   
       /**
  
  
  
  1.6       +9 -6      jakarta-commons/jelly/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestParser.java
  
  Index: TestParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jelly/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestParser.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- TestParser.java	9 Sep 2004 12:24:41 -0000	1.5
  +++ TestParser.java	28 Dec 2004 01:39:23 -0000	1.6
  @@ -26,6 +26,7 @@
   
   import org.apache.commons.jelly.Script;
   import org.apache.commons.jelly.Tag;
  +import org.apache.commons.jelly.JellyContext;
   import org.apache.commons.jelly.impl.ScriptBlock;
   import org.apache.commons.jelly.impl.TagScript;
   import org.apache.commons.jelly.parser.XMLParser;
  @@ -66,26 +67,28 @@
   
           log.debug("Found: " + script);
   
  -        assertTagsHaveParent( script, null );
  +        assertTagsHaveParent( script, null, null );
       }
   
       /**
        * Tests that the Tag in the TagScript has the given parent and then
        * recurse to check its children has the correct parent and so forth.
        */
  -    protected void assertTagsHaveParent(Script script, Tag parent) throws Exception {
  +    protected void assertTagsHaveParent(Script script, Tag parent, JellyContext context) throws Exception {
  +        if ( context == null )
  +            context = new JellyContext();
           if ( script instanceof TagScript ) {
               TagScript tagScript = (TagScript) script;
  -            Tag tag = tagScript.getTag();
  +            Tag tag = tagScript.getTag(context);
   
               assertEquals( "Tag: " + tag + " has the incorrect parent", parent, tag.getParent() );
   
  -            assertTagsHaveParent( tag.getBody(), tag );
  +            assertTagsHaveParent( tag.getBody(), tag, context );
           }
           else if ( script instanceof ScriptBlock ) {
               ScriptBlock block = (ScriptBlock) script;
               for ( Iterator iter = block.getScriptList().iterator(); iter.hasNext(); ) {
  -                assertTagsHaveParent( (Script) iter.next(), parent );
  +                assertTagsHaveParent( (Script) iter.next(), parent, context );
               }
           }
       }
  
  
  
  1.7       +4 -4      jakarta-commons/jelly/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/TransformTag.java
  
  Index: TransformTag.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jelly/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/TransformTag.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- TransformTag.java	27 Oct 2004 21:51:13 -0000	1.6
  +++ TransformTag.java	28 Dec 2004 01:39:23 -0000	1.7
  @@ -372,7 +372,7 @@
   
                       Tag tag = null;
                       try {
  -                        tag = ((TagScript) script).getTag();
  +                        tag = ((TagScript) script).getTag(getContext());
                       } catch (JellyException e) {
                           throw new JellyTagException(e);
                       }
  @@ -414,7 +414,7 @@
       
                       Tag tag = null;
                       try {
  -                        tag = ((TagScript) script).getTag();
  +                        tag = ((TagScript) script).getTag(getContext());
                       } catch (JellyException e) {
                           throw new JellyTagException(e);
                       }
  
  
  
  1.1                  jakarta-commons/jelly/src/test/org/apache/commons/jelly/core/TestCoreMemoryLeak.java
  
  Index: TestCoreMemoryLeak.java
  ===================================================================
  /*
   * Copyright 2002,2004 The Apache Software Foundation.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.commons.jelly.core;
  
  /** Tests for basic memory leaking in core tags. Runs a few test scripts many times.
   * @author Hans Gilde
   *
   */
  public class TestCoreMemoryLeak extends BaseMemoryLeakTest {
  
      /** The JUnit constructor.
       * @param name
       */
      public TestCoreMemoryLeak(String name) {
          super(name);
      }
      
      public void testBasicScriptForLeak() throws Exception {
          assertTrue(runScriptManyTimes("c.jelly", 10000) < 200000);
      }
  
  }
  
  
  
  1.1                  jakarta-commons/jelly/src/test/org/apache/commons/jelly/core/BaseMemoryLeakTest.java
  
  Index: BaseMemoryLeakTest.java
  ===================================================================
  /*
   * Copyright 2002,2004 The Apache Software Foundation.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.commons.jelly.core;
  
  import java.io.ByteArrayInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.net.URL;
  
  import junit.framework.TestCase;
  
  import org.apache.commons.jelly.JellyContext;
  import org.apache.commons.jelly.JellyException;
  import org.apache.commons.jelly.Script;
  import org.apache.commons.jelly.XMLOutput;
  import org.apache.commons.jelly.parser.XMLParser;
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  
  /**
   * Automates the basic process of testing a tag library for a memory leak.
   * <p>
   * To use it, extend it. Use the {@link runScriptManyTimes(String, int)}
   * method in your unit tests.
   * 
   * @author Hans Gilde
   *  
   */
  public class BaseMemoryLeakTest extends TestCase {
      private final static Log log = LogFactory.getLog(BaseMemoryLeakTest.class);
  
      /**
       * The JUnit constructor
       * 
       * @param name
       */
      public BaseMemoryLeakTest(String name) {
          super(name);
      }
  
      /** Runs a script count times and reports the number of bytes "leaked".
       * Note that "leaked" means "not collected by the GC"
       * and can easily be different between JVM's. This is because all 
       * freed references may not be available for GC in the short time
       * between their freeing and the completion of this test.
       * <p/>
       * However, running a 
       * script 10,000 or 100,000 times should be a pretty good test
       * for a memory leak. If there's not too much memory "leaked",
       * you're probably OK.
       * @param scriptName The path to the script, from the classloader of the current class.
       * @param count The number of times to run the script.
       * @return The number of bytes "leaked"
       * @throws IOException
       * @throws SAXException
       * @throws JellyException
       */
      public long runScriptManyTimes(String scriptName, int count)
              throws IOException, SAXException, JellyException {
          Runtime rt = Runtime.getRuntime();
          JellyContext jc = new JellyContext();
          jc.setClassLoader(getClass().getClassLoader());
  
          XMLOutput output = XMLOutput.createDummyXMLOutput();
          
          URL url = this.getClass().getResource(scriptName);
  
          String exturl = url.toExternalForm();
          int lastSlash = exturl.lastIndexOf("/");
          String extBase = exturl.substring(0,lastSlash+1);
          URL baseurl = new URL(extBase);
          jc.setCurrentURL(baseurl);
          
          InputStream is = url.openStream();
          byte[] bytes = new byte[is.available()];
          is.read(bytes);
  
          InputStream scriptIStream = new ByteArrayInputStream(bytes);
          InputSource scriptISource = new InputSource(scriptIStream);
  
          is.close();
          is = null;
          bytes = null;
  
          rt.runFinalization();
          rt.gc();
  
          long start = rt.totalMemory() - rt.freeMemory();
          log.info("Starting memory test with used memory of " + start);
  
          XMLParser parser;
          Script script;
  
          int outputEveryXIterations = outputEveryXIterations();
  
          for (int i = 0; i < count; i++) {
              scriptIStream.reset();
              parser = new XMLParser();
  
              script = parser.parse(scriptISource);
              script.run(jc, output);
  			log.info("TagHolderMap has " + jc.getTagHolderMap().size() + " entries.");
  			// PL: I don't see why but removing the clear here 
  			//     does make the test fail!
  			//     As if the WeakHashMap wasn't weak enough...
  			jc.clear();
  
              if (outputEveryXIterations != 0 && i % outputEveryXIterations == 0) {
                  parser = null;
                  script = null;
                  
                  rt.runFinalization();
                  rt.gc();
                  long middle = rt.totalMemory() - rt.freeMemory();
                  log.info("Memory test after " + i + " runs: "
                          + (middle - start));
              }
          }
          
          rt.gc();
  
          jc = null;
          output = null;
          parser = null;
          script = null;
  
          scriptIStream = null;
          scriptISource = null;
  
          rt.runFinalization();
          rt.gc();
          
          long nullsDone = rt.totalMemory() - rt.freeMemory();
          log.info("Memory test completed, memory \"leaked\": " + (nullsDone - start));
          
          return nullsDone - start;
      }
  
      protected int outputEveryXIterations() {
          return 1000;
      }
  
  }
  
  
  
  1.2       +1 -10     jakarta-commons/jelly/src/java/org/apache/commons/jelly/util/TagUtils.java
  
  Index: TagUtils.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/jelly/src/java/org/apache/commons/jelly/util/TagUtils.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TagUtils.java	27 Oct 2004 21:49:28 -0000	1.1
  +++ TagUtils.java	28 Dec 2004 01:39:23 -0000	1.2
  @@ -20,7 +20,6 @@
   import org.apache.commons.jelly.impl.CompositeTextScriptBlock;
   import org.apache.commons.jelly.impl.ScriptBlock;
   import org.apache.commons.jelly.impl.TextScript;
  -import org.apache.commons.jelly.impl.WeakReferenceWrapperScript;
   
   /** Contains static methods to help tag developers.
    * @author Hans Gilde
  @@ -36,15 +35,7 @@
        */
       public static void trimScript(Script body) {
           synchronized(body) {
  -            if (body instanceof WeakReferenceWrapperScript) {
  -                WeakReferenceWrapperScript wrrs = (WeakReferenceWrapperScript) body;
  -                try {
  -                    wrrs.trimWhitespace();
  -                } catch (JellyTagException e) {
  -                    //TODO handle this exception once the Tag interface allows JellyTagException to be thrown
  -                    return;
  -                }
  -            } else if ( body instanceof CompositeTextScriptBlock ) {
  +            if ( body instanceof CompositeTextScriptBlock ) {
                   CompositeTextScriptBlock block = (CompositeTextScriptBlock) body;
                   block.trimWhitespace();
               }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: cvs commit: jakarta-commons/jelly/src/java/org/apache/commons/jelly/util TagUtils.java

Posted by Brett Porter <br...@apache.org>.
>>
>> - Windows, (Sun's?) JDK 1.4.2 _06, memory usage of about 2.4 Mb
>
>
> I have a felling this garbage collects far less often. I also have a 
> GB of RAM, so it probably didn't feel it had to. Try System.gc() 
> before calling the *Memory() functions.

Oh, I see that you did have rt.gc() ;)

I don't know what was going on. I've tried again and now get:
INFO: Memory test completed, memory "leaked": 62648

On JDK 1.5.0:
INFO: Memory test completed, memory "leaked": -14272

hmmm....

>
>> Do maven experts have an easy way for me in maven to run a unit test 
>> with profiling option -Xprof on ?
>
>
> I think its
> maven.junit.fork=true
> maven.junit.jvmargs=-Xprof
>
> Try the test plugin properties reference.
>
> Cheers,
> Brett
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: cvs commit: jakarta-commons/jelly/src/java/org/apache/commons/jelly/util TagUtils.java

Posted by Brett Porter <br...@apache.org>.
Paul Libbrecht wrote:

>
> The result is quite amazing... here's my current survey of the 
> memory-usages of running the script <J:jelly><j:set var="c" 
> value="true"/></j:jelly> 10000 times.
> The memory usage is computed from the difference 
> Runtime.totalMemory()-Runtime.freeMemory() between the start and after 
> 10000 runs.
>
> - Windows, (Sun's?) JDK 1.4.2 _06, memory usage of about 2.4 Mb

I have a felling this garbage collects far less often. I also have a GB 
of RAM, so it probably didn't feel it had to. Try System.gc() before 
calling the *Memory() functions.

> Do maven experts have an easy way for me in maven to run a unit test 
> with profiling option -Xprof on ?

I think its
maven.junit.fork=true
maven.junit.jvmargs=-Xprof

Try the test plugin properties reference.

Cheers,
Brett

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: cvs commit: jakarta-commons/jelly/src/java/org/apache/commons/jelly/util TagUtils.java

Posted by Paul Libbrecht <pa...@activemath.org>.
The result is quite amazing... here's my current survey of the 
memory-usages of running the script <J:jelly><j:set var="c" 
value="true"/></j:jelly> 10000 times.
The memory usage is computed from the difference 
Runtime.totalMemory()-Runtime.freeMemory() between the start and after 
10000 runs.

- Windows, (Sun's?) JDK 1.4.2 _06, memory usage of about 2.4 Mb
- Linux, JDK 1.4.2 _02, memory usage of about 48 Kb (honest!)
- MacOSX, JDK 1.4.2 _05, memory usage of about 96 kb (same original 
codebase, I think)
- Linux, JDK 1.3.1 _06, usage 6 kb
- Linux, JDK 1.5.0 0b64 usage 67 kb

The difference between the platforms is somewhat enormous!
I played a bit more with the test... Added a simple instance counter 
for the number of live instances of TagSupport and... it does not grow! 
(but fails after inserting this!).
In all cases, the used-memory keeps growing... any "optimizer" effect ?

Do maven experts have an easy way for me in maven to run a unit test 
with profiling option -Xprof on ?

thanks

paul


Le 28 déc. 04, à 23:49, Brett Porter a écrit :

> No problem - hopefully it remains attached.
>
> Let me know if you need any more info. It was run using Maven 1.0.2 as 
> "maven clean jar:install" off the latest CVS. I didn't really change 
> anything since the last time I built it.
>
> - Brett
>
> Paul Libbrecht wrote:
>
>>
>> Le 28 déc. 04, à 10:13, Brett Porter a écrit :
>>
>>>> can you document more your platform and VM...
>>>
>>> Windows, Sun Java 1.4.2_06
>>
>>
>> If possible, I'd get a copy of your failure to help me fix it... I 
>> think it's a good test that should prove the absence of leaking.
>>
>>>> [...] Also, maybe it should be renamed as 
>>>> OptionalTestCoreMemoryLeak and only run when one wants ? (it is 
>>>> very slow anyways).
>>>
>>> I think this is a good idea.
>>
>>
>> I've disabled it in project.xml for now hoping to make it mainstream 
>> soon.
>>
>> thanks
>>
>> paul
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
>> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>>
>>
>
> <TEST-org.apache.commons.jelly.core.TestCoreMemoryLeak.txt.gz>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: cvs commit: jakarta-commons/jelly/src/java/org/apache/commons/jelly/util TagUtils.java

Posted by Brett Porter <br...@apache.org>.
No problem - hopefully it remains attached.

Let me know if you need any more info. It was run using Maven 1.0.2 as 
"maven clean jar:install" off the latest CVS. I didn't really change 
anything since the last time I built it.

- Brett

Paul Libbrecht wrote:

>
> Le 28 déc. 04, à 10:13, Brett Porter a écrit :
>
>>> can you document more your platform and VM...
>>
>> Windows, Sun Java 1.4.2_06
>
>
> If possible, I'd get a copy of your failure to help me fix it... I 
> think it's a good test that should prove the absence of leaking.
>
>>> [...] Also, maybe it should be renamed as OptionalTestCoreMemoryLeak 
>>> and only run when one wants ? (it is very slow anyways).
>>
>> I think this is a good idea.
>
>
> I've disabled it in project.xml for now hoping to make it mainstream 
> soon.
>
> thanks
>
> paul
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>
>


Re: cvs commit: jakarta-commons/jelly/src/java/org/apache/commons/jelly/util TagUtils.java

Posted by Paul Libbrecht <pa...@activemath.org>.
Le 28 déc. 04, à 10:13, Brett Porter a écrit :

>> can you document more your platform and VM...
> Windows, Sun Java 1.4.2_06

If possible, I'd get a copy of your failure to help me fix it... I 
think it's a good test that should prove the absence of leaking.

>> [...] Also, maybe it should be renamed as OptionalTestCoreMemoryLeak 
>> and only run when one wants ? (it is very slow anyways).
> I think this is a good idea.

I've disabled it in project.xml for now hoping to make it mainstream 
soon.

thanks

paul


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: cvs commit: jakarta-commons/jelly/src/java/org/apache/commons/jelly/util TagUtils.java

Posted by Brett Porter <br...@apache.org>.
Paul Libbrecht wrote:

> Mmmmh....
> can you document more your platform and VM...


Windows, Sun Java 1.4.2_06

> This test is based on freemem() and that makes, of course, the 
> assertion quite heuristic... if we all provide numbers for each 
> platforms, maybe we find a way to adjust the heuristic ?
>
> Also, maybe it should be renamed as OptionalTestCoreMemoryLeak and 
> only run when one wants ? (it is very slow anyways).

I think this is a good idea.

- Brett

>
> paul
>
>
> Le 28 déc. 04, à 02:48, Brett Porter a écrit :
>
>> The test is failing for me. Is that to be expected?
>> polx@apache.org wrote:
>>
>>>  Added:       jelly/src/test/org/apache/commons/jelly/core
>>>                        TestCoreMemoryLeak.java BaseMemoryLeakTest.java
>>>  Removed:     jelly/src/java/org/apache/commons/jelly/impl
>>>                        WeakReferenceWrapperScript.java
>>>  Log:
>>>  Tag caching is now done in the JellyContext.
>>>  The TestCoreMemoryLeak shows that, at least with some usage of 
>>> JellyContext.clear(), one avoids leaks.
>>>  Removing Tag-caching flag. Also, removing the 
>>> WeakReferenceWrapperScript, both were in the era of ThreadLocal 
>>> which is to be finished.
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: cvs commit: jakarta-commons/jelly/src/java/org/apache/commons/jelly/util TagUtils.java

Posted by Paul Libbrecht <pa...@activemath.org>.
Mmmmh....
can you document more your platform and VM...
This test is based on freemem() and that makes, of course, the 
assertion quite heuristic... if we all provide numbers for each 
platforms, maybe we find a way to adjust the heuristic ?

Also, maybe it should be renamed as OptionalTestCoreMemoryLeak and only 
run when one wants ? (it is very slow anyways).

paul


Le 28 déc. 04, à 02:48, Brett Porter a écrit :
> The test is failing for me. Is that to be expected?
> polx@apache.org wrote:
>>  Added:       jelly/src/test/org/apache/commons/jelly/core
>>                        TestCoreMemoryLeak.java BaseMemoryLeakTest.java
>>  Removed:     jelly/src/java/org/apache/commons/jelly/impl
>>                        WeakReferenceWrapperScript.java
>>  Log:
>>  Tag caching is now done in the JellyContext.
>>  The TestCoreMemoryLeak shows that, at least with some usage of 
>> JellyContext.clear(), one avoids leaks.
>>  Removing Tag-caching flag. Also, removing the 
>> WeakReferenceWrapperScript, both were in the era of ThreadLocal which 
>> is to be finished.


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: cvs commit: jakarta-commons/jelly/src/java/org/apache/commons/jelly/util TagUtils.java

Posted by Brett Porter <br...@apache.org>.
The test is failing for me. Is that to be expected?

polx@apache.org wrote:

>polx        2004/12/27 17:39:23
>
>  Modified:    jelly/src/java/org/apache/commons/jelly/impl
>                        StaticTagScript.java TagScript.java
>               jelly/src/java/org/apache/commons/jelly JellyContext.java
>               jelly/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml
>                        TestParser.java
>               jelly/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml
>                        TransformTag.java
>               jelly/src/java/org/apache/commons/jelly/util TagUtils.java
>  Added:       jelly/src/test/org/apache/commons/jelly/core
>                        TestCoreMemoryLeak.java BaseMemoryLeakTest.java
>  Removed:     jelly/src/java/org/apache/commons/jelly/impl
>                        WeakReferenceWrapperScript.java
>  Log:
>  Tag caching is now done in the JellyContext.
>  The TestCoreMemoryLeak shows that, at least with some usage of JellyContext.clear(), one avoids leaks.
>  Removing Tag-caching flag. Also, removing the WeakReferenceWrapperScript, both were in the era of ThreadLocal which is to be finished.
>  
>  Have tested these with an amount of the tag-libs... had to change the XML one but otherwise apparently none.
>  
>  Feedback and testing eagerly welcome!
>  paul
>  
>  Revision  Changes    Path
>  1.25      +2 -2      jakarta-commons/jelly/src/java/org/apache/commons/jelly/impl/StaticTagScript.java
>  
>  Index: StaticTagScript.java
>  ===================================================================
>  RCS file: /home/cvs/jakarta-commons/jelly/src/java/org/apache/commons/jelly/impl/StaticTagScript.java,v
>  retrieving revision 1.24
>  retrieving revision 1.25
>  diff -u -r1.24 -r1.25
>  --- StaticTagScript.java	16 Sep 2004 01:12:11 -0000	1.24
>  +++ StaticTagScript.java	28 Dec 2004 01:39:22 -0000	1.25
>  @@ -59,14 +59,14 @@
>   
>           Tag tag = null;
>           try {
>  -            tag = getTag();
>  +            tag = getTag(context);
>   
>               // lets see if we have a dynamic tag
>               if (tag instanceof StaticTag) {
>                   tag = findDynamicTag(context, (StaticTag) tag);
>               }
>   
>  -            setTag(tag);
>  +            setTag(tag,context);
>           } catch (JellyException e) {
>               throw new JellyTagException(e);
>           }
>  
>  
>  
>  1.47      +12 -31    jakarta-commons/jelly/src/java/org/apache/commons/jelly/impl/TagScript.java
>  
>  Index: TagScript.java
>  ===================================================================
>  RCS file: /home/cvs/jakarta-commons/jelly/src/java/org/apache/commons/jelly/impl/TagScript.java,v
>  retrieving revision 1.46
>  retrieving revision 1.47
>  diff -u -r1.46 -r1.47
>  --- TagScript.java	27 Oct 2004 21:50:53 -0000	1.46
>  +++ TagScript.java	28 Dec 2004 01:39:22 -0000	1.47
>  @@ -61,15 +61,6 @@
>       /** The Log to which logging calls will be made. */
>       private static final Log log = LogFactory.getLog(TagScript.class);
>   
>  -    /**
>  -     * Thread local storage for the tag used by the current thread.
>  -     * This allows us to pool tag instances, per thread to reduce object construction
>  -     * over head, if we need it.
>  -     *
>  -     * Note that we could use the stack and create a new tag for each invocation
>  -     * if we made a slight change to the Script API to pass in the parent tag.
>  -     */
>  -    private ThreadLocal tagHolder = new ThreadLocal();
>   
>       /** The attribute expressions that are created */
>       protected Map attributes = new Hashtable();
>  @@ -194,11 +185,8 @@
>       public void run(JellyContext context, XMLOutput output) throws JellyTagException {
>           URL rootURL = context.getRootURL();
>           URL currentURL = context.getCurrentURL();
>  -        if ( ! context.isCacheTags() ) {
>  -            clearTag();
>  -        }
>           try {
>  -            Tag tag = getTag();
>  +            Tag tag = getTag(context);
>               if ( tag == null ) {
>                   return;
>               }
>  @@ -295,15 +283,15 @@
>       /**
>        * @return the tag to be evaluated, creating it lazily if required.
>        */
>  -    public Tag getTag() throws JellyException {
>  -        Tag tag = (Tag) tagHolder.get();
>  +    public Tag getTag(JellyContext context) throws JellyException {
>  +        Tag tag = context.getTagOfTagScript(this);
>           if ( tag == null ) {
>               tag = createTag();
>               if ( tag != null ) {
>  -                tagHolder.set(tag);
>  +                context.setTagForScript(this,tag);
>               }
>           }
>  -        configureTag(tag);
>  +        configureTag(tag,context);
>           return tag;
>       }
>   
>  @@ -494,21 +482,20 @@
>           return null;
>       }
>   
>  -
>  +	
>       /**
>        * Compiles a newly created tag if required, sets its parent and body.
>        */
>  -    protected void configureTag(Tag tag) throws JellyException {
>  +    protected void configureTag(Tag tag, JellyContext context) throws JellyException {
>           if (tag instanceof CompilableTag) {
>               ((CompilableTag) tag).compile();
>           }
>           Tag parentTag = null;
>           if ( parent != null ) {
>  -            parentTag = parent.getTag();
>  +            parentTag = parent.getTag(context);
>           }
>           tag.setParent( parentTag );
>  -        tag.setBody( new WeakReferenceWrapperScript(tagBody) );
>  -        //tag.setBody( tagBody );
>  +        tag.setBody( tagBody );
>   
>           if (tag instanceof NamespaceAwareTag) {
>               NamespaceAwareTag naTag = (NamespaceAwareTag) tag;
>  @@ -519,19 +506,13 @@
>           }
>       }
>   
>  -    /**
>  -     * Flushes the current cached tag so that it will be created, lazily, next invocation
>  -     */
>  -    protected void clearTag() {
>  -        tagHolder.set(null);
>  -    }
>   
>       /**
>        * Allows the script to set the tag instance to be used, such as in a StaticTagScript
>        * when a StaticTag is switched with a DynamicTag
>        */
>  -    protected void setTag(Tag tag) {
>  -        tagHolder.set(tag);
>  +    protected void setTag(Tag tag, JellyContext context) {
>  +        context.setTagForScript(this,tag);
>       }
>   
>       /**
>  
>  
>  
>  1.62      +39 -27    jakarta-commons/jelly/src/java/org/apache/commons/jelly/JellyContext.java
>  
>  Index: JellyContext.java
>  ===================================================================
>  RCS file: /home/cvs/jakarta-commons/jelly/src/java/org/apache/commons/jelly/JellyContext.java,v
>  retrieving revision 1.61
>  retrieving revision 1.62
>  diff -u -r1.61 -r1.62
>  --- JellyContext.java	9 Sep 2004 15:10:03 -0000	1.61
>  +++ JellyContext.java	28 Dec 2004 01:39:23 -0000	1.62
>  @@ -25,6 +25,7 @@
>   import java.util.Map;
>   
>   import org.apache.commons.jelly.parser.XMLParser;
>  +import org.apache.commons.jelly.impl.TagScript;
>   import org.apache.commons.jelly.util.ClassLoaderUtils;
>   import org.apache.commons.logging.Log;
>   import org.apache.commons.logging.LogFactory;
>  @@ -90,8 +91,15 @@
>       /** Should we export tag libraries to our parents context */
>       private boolean exportLibraries = true;
>   
>  -    /** Should we cache Tag instances, per thread, to reduce object contruction overhead? */
>  -    private boolean cacheTags = false;
>  +    /** A map that associates TagScript objects to Tag objects.
>  +      * Is made a WeakHashMap so that the storage is discarded if the 
>  +      * Script is discarded.
>  +      */
>  +    private Map tagHolderMap = new java.util.WeakHashMap(5);
>  +    // THINKME: Script objects are like Object (for equals and hashCode) I think.
>  +    //          It should be asy to optimize hash-map distribution, e.g. by
>  +    //          shifting the hashcode return value (presuming Object.hashcode()
>  +    //          is something like an address)
>   
>       /**
>        * Create a new context with the currentURL set to the rootURL
>  @@ -133,7 +141,6 @@
>           this.rootURL = parent.rootURL;
>           this.currentURL = parent.currentURL;
>           this.variables.put("parentScope", parent.variables);
>  -        this.cacheTags = parent.cacheTags;
>           init();
>       }
>   
>  @@ -377,7 +384,36 @@
>       public JellyContext newJellyContext() {
>           return createChildContext();
>       }
>  +    
>   
>  +    /** @return the tag associated to the given TagScript for the current run.
>  +      */
>  +    public Tag getTagOfTagScript(TagScript script) {
>  +        if( script == null )
>  +            return null;
>  +        return (Tag) tagHolderMap.get(script);
>  +    }
>  +	
>  +	/** @return the Map that associates the the Tags to Scripts */
>  +	public Map getTagHolderMap() {
>  +		return tagHolderMap;
>  +	}
>  +    
>  +    /** Associates, for the run of this context, the tag of this TagScript.
>  +      */
>  +    public void setTagForScript(TagScript script, Tag tag) {
>  +        tagHolderMap.put(script,tag);
>  +    }
>  +    
>  +    /** Clears both the script-to-tags association and the variables association.
>  +      */
>  +    public void clear() {
>  +        tagHolderMap.clear();
>  +        variables.clear();
>  +    }
>  +    
>  +    
>  +    
>       /** Registers the given tag library against the given namespace URI.
>        * This should be called before the parser is used.
>        */
>  @@ -787,30 +823,6 @@
>        */
>       public void setCurrentURL(URL currentURL) {
>           this.currentURL = currentURL;
>  -    }
>  -
>  -    /**
>  -     * Returns whether caching of Tag instances, per thread, is enabled.
>  -     * Caching Tags can boost performance, on some JVMs, by reducing the cost of
>  -     * object construction when running Jelly inside a multi-threaded application server
>  -     * such as a Servlet engine.
>  -     *
>  -     * @return whether caching of Tag instances is enabled.
>  -     */
>  -    public boolean isCacheTags() {
>  -        return cacheTags;
>  -    }
>  -
>  -    /**
>  -     * Sets whether caching of Tag instances, per thread, is enabled.
>  -     * Caching Tags can boost performance, on some JVMs, by reducing the cost of
>  -     * object construction when running Jelly inside a multi-threaded application server
>  -     * such as a Servlet engine.
>  -     *
>  -     * @param cacheTags Whether caching should be enabled or disabled.
>  -     */
>  -    public void setCacheTags(boolean cacheTags) {
>  -        this.cacheTags = cacheTags;
>       }
>   
>       /**
>  
>  
>  
>  1.6       +9 -6      jakarta-commons/jelly/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestParser.java
>  
>  Index: TestParser.java
>  ===================================================================
>  RCS file: /home/cvs/jakarta-commons/jelly/jelly-tags/xml/src/test/org/apache/commons/jelly/tags/xml/TestParser.java,v
>  retrieving revision 1.5
>  retrieving revision 1.6
>  diff -u -r1.5 -r1.6
>  --- TestParser.java	9 Sep 2004 12:24:41 -0000	1.5
>  +++ TestParser.java	28 Dec 2004 01:39:23 -0000	1.6
>  @@ -26,6 +26,7 @@
>   
>   import org.apache.commons.jelly.Script;
>   import org.apache.commons.jelly.Tag;
>  +import org.apache.commons.jelly.JellyContext;
>   import org.apache.commons.jelly.impl.ScriptBlock;
>   import org.apache.commons.jelly.impl.TagScript;
>   import org.apache.commons.jelly.parser.XMLParser;
>  @@ -66,26 +67,28 @@
>   
>           log.debug("Found: " + script);
>   
>  -        assertTagsHaveParent( script, null );
>  +        assertTagsHaveParent( script, null, null );
>       }
>   
>       /**
>        * Tests that the Tag in the TagScript has the given parent and then
>        * recurse to check its children has the correct parent and so forth.
>        */
>  -    protected void assertTagsHaveParent(Script script, Tag parent) throws Exception {
>  +    protected void assertTagsHaveParent(Script script, Tag parent, JellyContext context) throws Exception {
>  +        if ( context == null )
>  +            context = new JellyContext();
>           if ( script instanceof TagScript ) {
>               TagScript tagScript = (TagScript) script;
>  -            Tag tag = tagScript.getTag();
>  +            Tag tag = tagScript.getTag(context);
>   
>               assertEquals( "Tag: " + tag + " has the incorrect parent", parent, tag.getParent() );
>   
>  -            assertTagsHaveParent( tag.getBody(), tag );
>  +            assertTagsHaveParent( tag.getBody(), tag, context );
>           }
>           else if ( script instanceof ScriptBlock ) {
>               ScriptBlock block = (ScriptBlock) script;
>               for ( Iterator iter = block.getScriptList().iterator(); iter.hasNext(); ) {
>  -                assertTagsHaveParent( (Script) iter.next(), parent );
>  +                assertTagsHaveParent( (Script) iter.next(), parent, context );
>               }
>           }
>       }
>  
>  
>  
>  1.7       +4 -4      jakarta-commons/jelly/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/TransformTag.java
>  
>  Index: TransformTag.java
>  ===================================================================
>  RCS file: /home/cvs/jakarta-commons/jelly/jelly-tags/xml/src/java/org/apache/commons/jelly/tags/xml/TransformTag.java,v
>  retrieving revision 1.6
>  retrieving revision 1.7
>  diff -u -r1.6 -r1.7
>  --- TransformTag.java	27 Oct 2004 21:51:13 -0000	1.6
>  +++ TransformTag.java	28 Dec 2004 01:39:23 -0000	1.7
>  @@ -372,7 +372,7 @@
>   
>                       Tag tag = null;
>                       try {
>  -                        tag = ((TagScript) script).getTag();
>  +                        tag = ((TagScript) script).getTag(getContext());
>                       } catch (JellyException e) {
>                           throw new JellyTagException(e);
>                       }
>  @@ -414,7 +414,7 @@
>       
>                       Tag tag = null;
>                       try {
>  -                        tag = ((TagScript) script).getTag();
>  +                        tag = ((TagScript) script).getTag(getContext());
>                       } catch (JellyException e) {
>                           throw new JellyTagException(e);
>                       }
>  
>  
>  
>  1.1                  jakarta-commons/jelly/src/test/org/apache/commons/jelly/core/TestCoreMemoryLeak.java
>  
>  Index: TestCoreMemoryLeak.java
>  ===================================================================
>  /*
>   * Copyright 2002,2004 The Apache Software Foundation.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
>   * You may obtain a copy of the License at
>   *
>   *      http://www.apache.org/licenses/LICENSE-2.0
>   *
>   * Unless required by applicable law or agreed to in writing, software
>   * distributed under the License is distributed on an "AS IS" BASIS,
>   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>   * See the License for the specific language governing permissions and
>   * limitations under the License.
>   */
>  package org.apache.commons.jelly.core;
>  
>  /** Tests for basic memory leaking in core tags. Runs a few test scripts many times.
>   * @author Hans Gilde
>   *
>   */
>  public class TestCoreMemoryLeak extends BaseMemoryLeakTest {
>  
>      /** The JUnit constructor.
>       * @param name
>       */
>      public TestCoreMemoryLeak(String name) {
>          super(name);
>      }
>      
>      public void testBasicScriptForLeak() throws Exception {
>          assertTrue(runScriptManyTimes("c.jelly", 10000) < 200000);
>      }
>  
>  }
>  
>  
>  
>  1.1                  jakarta-commons/jelly/src/test/org/apache/commons/jelly/core/BaseMemoryLeakTest.java
>  
>  Index: BaseMemoryLeakTest.java
>  ===================================================================
>  /*
>   * Copyright 2002,2004 The Apache Software Foundation.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
>   * You may obtain a copy of the License at
>   *
>   *      http://www.apache.org/licenses/LICENSE-2.0
>   *
>   * Unless required by applicable law or agreed to in writing, software
>   * distributed under the License is distributed on an "AS IS" BASIS,
>   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>   * See the License for the specific language governing permissions and
>   * limitations under the License.
>   */
>  package org.apache.commons.jelly.core;
>  
>  import java.io.ByteArrayInputStream;
>  import java.io.IOException;
>  import java.io.InputStream;
>  import java.net.URL;
>  
>  import junit.framework.TestCase;
>  
>  import org.apache.commons.jelly.JellyContext;
>  import org.apache.commons.jelly.JellyException;
>  import org.apache.commons.jelly.Script;
>  import org.apache.commons.jelly.XMLOutput;
>  import org.apache.commons.jelly.parser.XMLParser;
>  import org.apache.commons.logging.Log;
>  import org.apache.commons.logging.LogFactory;
>  import org.xml.sax.InputSource;
>  import org.xml.sax.SAXException;
>  
>  /**
>   * Automates the basic process of testing a tag library for a memory leak.
>   * <p>
>   * To use it, extend it. Use the {@link runScriptManyTimes(String, int)}
>   * method in your unit tests.
>   * 
>   * @author Hans Gilde
>   *  
>   */
>  public class BaseMemoryLeakTest extends TestCase {
>      private final static Log log = LogFactory.getLog(BaseMemoryLeakTest.class);
>  
>      /**
>       * The JUnit constructor
>       * 
>       * @param name
>       */
>      public BaseMemoryLeakTest(String name) {
>          super(name);
>      }
>  
>      /** Runs a script count times and reports the number of bytes "leaked".
>       * Note that "leaked" means "not collected by the GC"
>       * and can easily be different between JVM's. This is because all 
>       * freed references may not be available for GC in the short time
>       * between their freeing and the completion of this test.
>       * <p/>
>       * However, running a 
>       * script 10,000 or 100,000 times should be a pretty good test
>       * for a memory leak. If there's not too much memory "leaked",
>       * you're probably OK.
>       * @param scriptName The path to the script, from the classloader of the current class.
>       * @param count The number of times to run the script.
>       * @return The number of bytes "leaked"
>       * @throws IOException
>       * @throws SAXException
>       * @throws JellyException
>       */
>      public long runScriptManyTimes(String scriptName, int count)
>              throws IOException, SAXException, JellyException {
>          Runtime rt = Runtime.getRuntime();
>          JellyContext jc = new JellyContext();
>          jc.setClassLoader(getClass().getClassLoader());
>  
>          XMLOutput output = XMLOutput.createDummyXMLOutput();
>          
>          URL url = this.getClass().getResource(scriptName);
>  
>          String exturl = url.toExternalForm();
>          int lastSlash = exturl.lastIndexOf("/");
>          String extBase = exturl.substring(0,lastSlash+1);
>          URL baseurl = new URL(extBase);
>          jc.setCurrentURL(baseurl);
>          
>          InputStream is = url.openStream();
>          byte[] bytes = new byte[is.available()];
>          is.read(bytes);
>  
>          InputStream scriptIStream = new ByteArrayInputStream(bytes);
>          InputSource scriptISource = new InputSource(scriptIStream);
>  
>          is.close();
>          is = null;
>          bytes = null;
>  
>          rt.runFinalization();
>          rt.gc();
>  
>          long start = rt.totalMemory() - rt.freeMemory();
>          log.info("Starting memory test with used memory of " + start);
>  
>          XMLParser parser;
>          Script script;
>  
>          int outputEveryXIterations = outputEveryXIterations();
>  
>          for (int i = 0; i < count; i++) {
>              scriptIStream.reset();
>              parser = new XMLParser();
>  
>              script = parser.parse(scriptISource);
>              script.run(jc, output);
>  			log.info("TagHolderMap has " + jc.getTagHolderMap().size() + " entries.");
>  			// PL: I don't see why but removing the clear here 
>  			//     does make the test fail!
>  			//     As if the WeakHashMap wasn't weak enough...
>  			jc.clear();
>  
>              if (outputEveryXIterations != 0 && i % outputEveryXIterations == 0) {
>                  parser = null;
>                  script = null;
>                  
>                  rt.runFinalization();
>                  rt.gc();
>                  long middle = rt.totalMemory() - rt.freeMemory();
>                  log.info("Memory test after " + i + " runs: "
>                          + (middle - start));
>              }
>          }
>          
>          rt.gc();
>  
>          jc = null;
>          output = null;
>          parser = null;
>          script = null;
>  
>          scriptIStream = null;
>          scriptISource = null;
>  
>          rt.runFinalization();
>          rt.gc();
>          
>          long nullsDone = rt.totalMemory() - rt.freeMemory();
>          log.info("Memory test completed, memory \"leaked\": " + (nullsDone - start));
>          
>          return nullsDone - start;
>      }
>  
>      protected int outputEveryXIterations() {
>          return 1000;
>      }
>  
>  }
>  
>  
>  
>  1.2       +1 -10     jakarta-commons/jelly/src/java/org/apache/commons/jelly/util/TagUtils.java
>  
>  Index: TagUtils.java
>  ===================================================================
>  RCS file: /home/cvs/jakarta-commons/jelly/src/java/org/apache/commons/jelly/util/TagUtils.java,v
>  retrieving revision 1.1
>  retrieving revision 1.2
>  diff -u -r1.1 -r1.2
>  --- TagUtils.java	27 Oct 2004 21:49:28 -0000	1.1
>  +++ TagUtils.java	28 Dec 2004 01:39:23 -0000	1.2
>  @@ -20,7 +20,6 @@
>   import org.apache.commons.jelly.impl.CompositeTextScriptBlock;
>   import org.apache.commons.jelly.impl.ScriptBlock;
>   import org.apache.commons.jelly.impl.TextScript;
>  -import org.apache.commons.jelly.impl.WeakReferenceWrapperScript;
>   
>   /** Contains static methods to help tag developers.
>    * @author Hans Gilde
>  @@ -36,15 +35,7 @@
>        */
>       public static void trimScript(Script body) {
>           synchronized(body) {
>  -            if (body instanceof WeakReferenceWrapperScript) {
>  -                WeakReferenceWrapperScript wrrs = (WeakReferenceWrapperScript) body;
>  -                try {
>  -                    wrrs.trimWhitespace();
>  -                } catch (JellyTagException e) {
>  -                    //TODO handle this exception once the Tag interface allows JellyTagException to be thrown
>  -                    return;
>  -                }
>  -            } else if ( body instanceof CompositeTextScriptBlock ) {
>  +            if ( body instanceof CompositeTextScriptBlock ) {
>                   CompositeTextScriptBlock block = (CompositeTextScriptBlock) body;
>                   block.trimWhitespace();
>               }
>  
>  
>  
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
>For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>
>
>  
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org