You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@velocity.apache.org by Will Glass-Husain <wg...@forio.com> on 2001/09/06 23:26:20 UTC

performance questions

Hi,

I'm seeing my servlet memory usage climb over time (with a fairly small user
base), and wondering if Velocity could be playing a role.  I'm using a
subclass of VelocityServlet, (velocity version 1.2-dev) on Apache Tomcat
3.2.3.

(1) Every time I upload a new JAR file with my servlet, my memory usage goes
up significantly.  Could there be some type of memory "leak" with either the
template cache or introspection?  (I've read the note in the Developer's
Guide on this and have turned caching on).

One hypothesis I have is that the Velocity singleton may be accumulating
unnecessary info when the Tomcat classloader reloads my JAR file.  Any ideas
on this?

(2) Going to new pages increases the memory usage.  Does the template cache
ever clear?

A note on my configuration.  I have no file "velocity.properties".  Instead,
I call the following code in the "loadConfiguration" method of my servlet.
(appended to the end of this message).  Not sure if this affects the memory
issue.

Appreciate any ideas.

Thanks, WILL

******
final public Properties loadConfiguration(ServletConfig cfg) {
 Properties p;

 p = new Properties();

 p.setProperty("file.resource.loader.path",
getInitParameter("TemplatePath"));
 p.setProperty("fileresource.loader.cache","true");
 p.setProperty("velocimacro.library","macro_library.fml");
 p.setProperty("velocimacro.permissions.allow.inline.local.scope","true");
 p.setProperty("runtime.log.invalid.references ","false");
 p.setProperty("resource.manager.logwhenfound","false");
 p.setProperty("runtime.log.logsystem.class",
"com.forio.servlet.ForioLogger");

 return p;
}


Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/8/01 7:38 AM, "Attila Szegedi" <sz...@freemail.hu> wrote:

> Adding a thought to my original posting:
> 
> the situation is even worse than I originally depicted, since keeping a
> Class object reachable not only prevents the class in question from
> unloading, it also prevents its class loader from being garbage collected,
> which in turn prevents *ALL OTHER CLASSES* loaded from the same class loader
> from unloading. So, Velocity's current method caching in Introspector will
> effectively cause all older code and their associated static structures to
> remain loaded in the VM when new code is loaded.

I realized this from your orignal posting... Hence my look at "#3"

geir


> 
> This is problem in all environments that support dynamic code reloading (so
> called "hot dispatch"), i.e. in Tomcat when a context is specified as
> reloadable="true".
> 
> Attila.
> 
> ----- Original Message -----
> From: "Attila Szegedi" <sz...@freemail.hu>
> To: <ve...@jakarta.apache.org>
> Sent: Friday, September 07, 2001 12:57 PM
> Subject: Re: performance questions
> 
> 
>> 
>> Introspector holds a strong reference to Class objects, so it prevents
> them
>> from being unloaded. This way, not only does it accumulate method cache
>> information, but it also keeps those classes around together with their
> code
>> and every object reachable from their static fields. And that can impose a
>> significant memory leak in an environment where classes are reloaded
>> frequently.
>> 
> 
> 

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Attila Szegedi <sz...@freemail.hu>.
----- Original Message -----
From: "Jon Stevens" <jo...@latchkey.com>
To: "velocity-user" <ve...@jakarta.apache.org>
Sent: Sunday, September 09, 2001 11:02 PM
Subject: Re: performance questions


> on 9/9/01 1:58 PM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:
>
> > I would be surprised if Tomcat dumped the entire webapp and everything
in it
> > because one class changes....
> >
> > geir
>
> It does. It has to.
>

I can also reinforce that. (Not that Jon needs reinforcement on this...)

> I have a terrible amount of experience in this because I implemented the
> session reloading for JServ and initially implemented it for Tomcat 3 as
> well. Session reloading is a pain in the ass because it has to
de-serialize
> all of your session objects *before* dumping the classloader and then
> re-serialize them *after* re-creating the classloader.

People not paying attention to their classes' serialVersionUIDs are in for a
surprise... :-)

>
> -jon
>

Attila.



Re: performance questions

Posted by Jon Stevens <jo...@latchkey.com>.
on 9/9/01 1:58 PM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:

> I would be surprised if Tomcat dumped the entire webapp and everything in it
> because one class changes....
> 
> geir

It does. It has to.

I have a terrible amount of experience in this because I implemented the
session reloading for JServ and initially implemented it for Tomcat 3 as
well. Session reloading is a pain in the ass because it has to de-serialize
all of your session objects *before* dumping the classloader and then
re-serialize them *after* re-creating the classloader.

-jon


Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/9/01 10:52 AM, "Jon Stevens" <jo...@latchkey.com> wrote:

> on 9/9/01 1:49 PM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:
> 
>> On 9/9/01 10:02 AM, "Jon Stevens" <jo...@latchkey.com> wrote:
>> 
>>> on 9/9/01 11:15 AM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:
>>> 
>>>> I don't think this works.  Velocity is traditionally used as a singleton
>>>> (the VelocityServelet uses the singleton model), so even if tomcat tosses
>>>> everything and reloads everything in WEB-INF/lib or WEB-INF/classes, the
>>>> living Velocity instance will persist.
>>> 
>>> If Velocity was first instantiated as a Singleton within the WEB-INF/lib or
>>> WEB-INF/classes classloader, then it would get dumped, regardless of the
>>> fact that it is a singleton.
>> 
>> Hm.  That's not my experience. I will double check.
>> 
>> geir
> 
> It is pretty simple:
> 
> If the reference to the classloader which loaded a class goes away, then
> everything within that classloader also goes away.

Like I said, that's not my experience, so I will double check. We aren't
talking about a new Velocity jar, but rather other jars or classes.

I would be surprised if Tomcat dumped the entire webapp and everything in it
because one class changes....

geir


-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Jon Stevens <jo...@latchkey.com>.
on 9/9/01 1:49 PM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:

> On 9/9/01 10:02 AM, "Jon Stevens" <jo...@latchkey.com> wrote:
> 
>> on 9/9/01 11:15 AM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:
>> 
>>> I don't think this works.  Velocity is traditionally used as a singleton
>>> (the VelocityServelet uses the singleton model), so even if tomcat tosses
>>> everything and reloads everything in WEB-INF/lib or WEB-INF/classes, the
>>> living Velocity instance will persist.
>> 
>> If Velocity was first instantiated as a Singleton within the WEB-INF/lib or
>> WEB-INF/classes classloader, then it would get dumped, regardless of the
>> fact that it is a singleton.
> 
> Hm.  That's not my experience. I will double check.
> 
> geir

It is pretty simple:

If the reference to the classloader which loaded a class goes away, then
everything within that classloader also goes away.

-jon


Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/9/01 10:02 AM, "Jon Stevens" <jo...@latchkey.com> wrote:

> on 9/9/01 11:15 AM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:
> 
>> I don't think this works.  Velocity is traditionally used as a singleton
>> (the VelocityServelet uses the singleton model), so even if tomcat tosses
>> everything and reloads everything in WEB-INF/lib or WEB-INF/classes, the
>> living Velocity instance will persist.
> 
> If Velocity was first instantiated as a Singleton within the WEB-INF/lib or
> WEB-INF/classes classloader, then it would get dumped, regardless of the
> fact that it is a singleton.

Hm.  That's not my experience. I will double check.

geir

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Jon Stevens <jo...@latchkey.com>.
on 9/9/01 11:15 AM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:

> I don't think this works.  Velocity is traditionally used as a singleton
> (the VelocityServelet uses the singleton model), so even if tomcat tosses
> everything and reloads everything in WEB-INF/lib or WEB-INF/classes, the
> living Velocity instance will persist.

If Velocity was first instantiated as a Singleton within the WEB-INF/lib or
WEB-INF/classes classloader, then it would get dumped, regardless of the
fact that it is a singleton.

-jon


Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/8/01 12:20 PM, "Attila Szegedi" <sz...@freemail.hu> wrote:

> Just an idea, maybe it will help you:
> 
> If Velocity was loaded through the same class loader through which your
> servlet is loaded, then the problem should not appear, since Velocity
> classes and objects would also get thrown away when Tomcat throws away the
> class loader on class reload.
> 
> To achieve this, place Velocity classes in the same location where your
> servlet classes are, and make sure Velocity is not accessible anywhere on
> Tomcat's or system's CLASSPATH.

I don't think this works.  Velocity is traditionally used as a singleton
(the VelocityServelet uses the singleton model), so even if tomcat tosses
everything and reloads everything in WEB-INF/lib or WEB-INF/classes, the
living Velocity instance will persist.

I use Velocity this way all the time - nothing (well, almost nothing) should
ever come from Tomcat's or the system classpath...

> 
> If this works, it would solve the problem without a need to modify Velocity
> code. However, I'll make the changes indicated earlier (lookup by qualified
> name and detection of reloads through stored.clazz != requested.clazz)
> because it has no performance impact (other than String.equals() being
> slower than Class.equals() for key lookup :-)), is elegant and eliminates
> memory leaks even if someone does not pay attention to load Velocity through
> disposable class loader.

I do have this working on top of the introspector changes needed for
separate runtime instance, and I am not thrilled with the String overhead
that is added.

I will keep testing...

geir

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Attila Szegedi <sz...@freemail.hu>.
Just an idea, maybe it will help you:

If Velocity was loaded through the same class loader through which your
servlet is loaded, then the problem should not appear, since Velocity
classes and objects would also get thrown away when Tomcat throws away the
class loader on class reload.

To achieve this, place Velocity classes in the same location where your
servlet classes are, and make sure Velocity is not accessible anywhere on
Tomcat's or system's CLASSPATH.

If this works, it would solve the problem without a need to modify Velocity
code. However, I'll make the changes indicated earlier (lookup by qualified
name and detection of reloads through stored.clazz != requested.clazz)
because it has no performance impact (other than String.equals() being
slower than Class.equals() for key lookup :-)), is elegant and eliminates
memory leaks even if someone does not pay attention to load Velocity through
disposable class loader.

Attila.



----- Original Message -----
From: "Will Glass-Husain" <wg...@forio.com>
To: <ve...@jakarta.apache.org>
Sent: Saturday, September 08, 2001 10:51 PM
Subject: RE: performance questions


> Attila,
>
> That explains a lot.  This is exactly my situation.  I have a significant
> number of classes that are loaded by my Servlet, and are apparently being
> accumulated whenever I reload my servlet.
>
> In an ideal world I would not worry about this as eventually we will have
a
> stable code base and would not need to update the classes.  However...
> Practically speaking, we will have bug fixes and new features regularly
for
> some time to come.  It would be helpful to do periodic updates without
> restarting Tomcat.
>
>
> WILL
>
>
> -----Original Message-----
> From: Attila Szegedi [mailto:szegedia@freemail.hu]
> Sent: Saturday, September 08, 2001 10:38 AM
> To: velocity-user@jakarta.apache.org
> Subject: Re: performance questions
>
>
> Adding a thought to my original posting:
>
> the situation is even worse than I originally depicted, since keeping a
> Class object reachable not only prevents the class in question from
> unloading, it also prevents its class loader from being garbage collected,
> which in turn prevents *ALL OTHER CLASSES* loaded from the same class
loader
> from unloading. So, Velocity's current method caching in Introspector will
> effectively cause all older code and their associated static structures to
> remain loaded in the VM when new code is loaded.
>
> This is problem in all environments that support dynamic code reloading
(so
> called "hot dispatch"), i.e. in Tomcat when a context is specified as
> reloadable="true".
>
> Attila.
>
> ----- Original Message -----
> From: "Attila Szegedi" <sz...@freemail.hu>
> To: <ve...@jakarta.apache.org>
> Sent: Friday, September 07, 2001 12:57 PM
> Subject: Re: performance questions
>
>
> >
> > Introspector holds a strong reference to Class objects, so it prevents
> them
> > from being unloaded. This way, not only does it accumulate method cache
> > information, but it also keeps those classes around together with their
> code
> > and every object reachable from their static fields. And that can impose
a
> > significant memory leak in an environment where classes are reloaded
> > frequently.
> >
>
>
>


RE: performance questions

Posted by Will Glass-Husain <wg...@forio.com>.
Attila,

That explains a lot.  This is exactly my situation.  I have a significant
number of classes that are loaded by my Servlet, and are apparently being
accumulated whenever I reload my servlet.

In an ideal world I would not worry about this as eventually we will have a
stable code base and would not need to update the classes.  However...
Practically speaking, we will have bug fixes and new features regularly for
some time to come.  It would be helpful to do periodic updates without
restarting Tomcat.


WILL


-----Original Message-----
From: Attila Szegedi [mailto:szegedia@freemail.hu]
Sent: Saturday, September 08, 2001 10:38 AM
To: velocity-user@jakarta.apache.org
Subject: Re: performance questions


Adding a thought to my original posting:

the situation is even worse than I originally depicted, since keeping a
Class object reachable not only prevents the class in question from
unloading, it also prevents its class loader from being garbage collected,
which in turn prevents *ALL OTHER CLASSES* loaded from the same class loader
from unloading. So, Velocity's current method caching in Introspector will
effectively cause all older code and their associated static structures to
remain loaded in the VM when new code is loaded.

This is problem in all environments that support dynamic code reloading (so
called "hot dispatch"), i.e. in Tomcat when a context is specified as
reloadable="true".

Attila.

----- Original Message -----
From: "Attila Szegedi" <sz...@freemail.hu>
To: <ve...@jakarta.apache.org>
Sent: Friday, September 07, 2001 12:57 PM
Subject: Re: performance questions


>
> Introspector holds a strong reference to Class objects, so it prevents
them
> from being unloaded. This way, not only does it accumulate method cache
> information, but it also keeps those classes around together with their
code
> and every object reachable from their static fields. And that can impose a
> significant memory leak in an environment where classes are reloaded
> frequently.
>



Re: performance questions

Posted by Attila Szegedi <sz...@freemail.hu>.
Adding a thought to my original posting:

the situation is even worse than I originally depicted, since keeping a
Class object reachable not only prevents the class in question from
unloading, it also prevents its class loader from being garbage collected,
which in turn prevents *ALL OTHER CLASSES* loaded from the same class loader
from unloading. So, Velocity's current method caching in Introspector will
effectively cause all older code and their associated static structures to
remain loaded in the VM when new code is loaded.

This is problem in all environments that support dynamic code reloading (so
called "hot dispatch"), i.e. in Tomcat when a context is specified as
reloadable="true".

Attila.

----- Original Message -----
From: "Attila Szegedi" <sz...@freemail.hu>
To: <ve...@jakarta.apache.org>
Sent: Friday, September 07, 2001 12:57 PM
Subject: Re: performance questions


>
> Introspector holds a strong reference to Class objects, so it prevents
them
> from being unloaded. This way, not only does it accumulate method cache
> information, but it also keeps those classes around together with their
code
> and every object reachable from their static fields. And that can impose a
> significant memory leak in an environment where classes are reloaded
> frequently.
>


Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/9/01 11:39 AM, "Bojan Smojver" <bo...@binarix.com> wrote:

> Attila Szegedi wrote:
>> 
>> Geir and I are now on a different track: essentially we'll assume in
>> Introspector code that class reloading happened if introspection is
>> requested for a class, and the Introspector detects it already has a
>> *different* (probably the old version) Class object with same qualified name
>> as the actually requested class.
>> 
>> It is somewhat worse than using weak references, as Introspector will
>> release the old classes only when it first encounters any of the new classes
>> and not immediately after Tomcat threw away the class loader (here
>> "immediately" naturally means "as soon as GC notices it"), however it has
>> the advantage of having no negative memory or performance impact on behalf
>> of Introspector.
>> 
>> I guess that this "next time reloaded class is accessed from Velocity
>> template" is an acceptable upper time limit for releasing old classes. If
>> it's not good enough for your needs, you can always stimulate the
>> Introspector to notice class reloads by processing a template that accesses
>> your reloadable classes when the reload occurs. That is, if you have means
>> for executing code on class reloads.
> 
> Not 100% sure on that one. It seems that at least Tomcat 3.3 drops the
> whole app when there is a new class. I just tested a few times and
> Tomcat reports removal and addition of context. The init methods of my
> beans get called every time I distribute and new class files (the init
> methods are called only when there are no stored beans in
> ServletContext/HttpSession). So, I guess Tomcat is taking care of all
> that, I hope at least...
> 
> Velocity, however, doesn't report a reload (I'm using non-singleton
> model), although I have this in the servlet init():
> 
> ----------------------------------------
> /* Initialise Velocity */
> ve=new VelocityEngine();
> ve.init(p);
> ----------------------------------------
> 
> and Tomcat reports that the init of the servlet was executed. A bit
> confusing...


One solution to this *whole* problem that requires no changes whatsoever is
to switch (or offer another) VelocityServlet to *not* use the Singleton, but
use the separable runtime instance.  That way, when the servlet gets tossed,
so does Velocity, completely and cleanly.  No muss, no fuss, no changes
required.

Attila sent me another patch that removes the sophisticated dumping, and
just dumps all, something which I advocated earlier, as we should not try to
out-guess our environment, and KISS.

I have a small commit that brings the Introspector out of Singleton pattern
and becomes a member of the RuntimeInstance (this is just to complete the
separable runtime work...).  I want to get this in as a baseline.  I will
then add Attila patch.

My own tests showed that using the String appeared slower, but Attila did
some rearrangement that got rid of some synch blocks, so while the String
penalty seemed small, we can handwave in the benefit that in a multithreded
environment, the benefit of less synchronization outweighs the small
apparent overhead of the String keys.

geir


-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/9/01 11:44 AM, "Bojan Smojver" <bo...@binarix.com> wrote:

> Jon Stevens wrote:
>> 
>> on 9/9/01 2:39 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
>> 
>>> Velocity, however, doesn't report a reload (I'm using non-singleton
>>> model), although I have this in the servlet init():
>>> 
>>> ----------------------------------------
>>> /* Initialise Velocity */
>>> ve=new VelocityEngine();
>>> ve.init(p);
>>> ----------------------------------------
>>> 
>>> and Tomcat reports that the init of the servlet was executed. A bit
>>> confusing...
>>> 
>>> Bojan
>> 
>> Where is your velocity.jar?
>> 
>> -jon
> 
> In Tomcat's lib/apps directory.

Ah. 

I always keep mine in WEB-INF/lib.  I believe y'all, but still wish to prove
it to correct my mental model.

Geir

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
Bojan Smojver wrote:
> 
> Bojan Smojver wrote:
> >
> > Jon Stevens wrote:
> > >
> > > on 9/9/01 2:44 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> > >
> > > > Jon Stevens wrote:
> > > >>
> > > >> on 9/9/01 2:39 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> > > >>
> > > >>> Velocity, however, doesn't report a reload (I'm using non-singleton
> > > >>> model), although I have this in the servlet init():
> > > >>>
> > > >>> ----------------------------------------
> > > >>> /* Initialise Velocity */
> > > >>> ve=new VelocityEngine();
> > > >>> ve.init(p);
> > > >>> ----------------------------------------
> > > >>>
> > > >>> and Tomcat reports that the init of the servlet was executed. A bit
> > > >>> confusing...
> > > >>>
> > > >>> Bojan
> > > >>
> > > >> Where is your velocity.jar?
> > > >>
> > > >> -jon
> > > >
> > > > In Tomcat's lib/apps directory.
> > > >
> > > > Bojan
> > >
> > > That explains it.
> > >
> > > Tomcat doesn't dump that classloader on a reload.
> > >
> > > It *only* dumps WEB-INF/lib and WEB-INF/classes
> > >
> > > -jon
> >
> > I wasn't really expecting that the lib/apps would get dumped. My
> > question is more along the lines of the VelocitEngine.init() not
> > reporting creation of parsers etc. I'm calling init() on a brand new
> > VelocityEngine object, so unless init stuff was cached somewhere...
> >
> > Bojan
> 
> Just had a peek into Velocity code...
> 
> VelocityEngine creates a RuntimeInstance object and stores it into a
> private class variable. When VelocityEngine's init runs, it just calls
> RuntimeInstance's init, which checks the initialized boolean variable
> (also private class variable) and if that's false (which should be for a
> brand new object, right?), it should print out 'RuntimeInstance v1.2x
> initializing' and so on.
> 
> How come I don't have that in the log files every time
> VelocityEngine.init() gets executed? Or better still, maybe the thing
> doesn't get executed although Tomcat says it does...
> 
> That's what's confusing me. I don't think that would have to do with
> classloaders at all.
> 
> Bojan

Don't worry about this one. Just found out what it was... and it's a
'tail -f' thing. The log file gets truncated and by the time tail gets
around to display the content, the init stuff is already too far above.
Once I opened up the file with less, I've realized that I'm a total and
complete *IDIOT*.

At least I know a bit more about Velocity init sequence :-)

Bojan

Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
Bojan Smojver wrote:
> 
> Jon Stevens wrote:
> >
> > on 9/9/01 2:44 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> >
> > > Jon Stevens wrote:
> > >>
> > >> on 9/9/01 2:39 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> > >>
> > >>> Velocity, however, doesn't report a reload (I'm using non-singleton
> > >>> model), although I have this in the servlet init():
> > >>>
> > >>> ----------------------------------------
> > >>> /* Initialise Velocity */
> > >>> ve=new VelocityEngine();
> > >>> ve.init(p);
> > >>> ----------------------------------------
> > >>>
> > >>> and Tomcat reports that the init of the servlet was executed. A bit
> > >>> confusing...
> > >>>
> > >>> Bojan
> > >>
> > >> Where is your velocity.jar?
> > >>
> > >> -jon
> > >
> > > In Tomcat's lib/apps directory.
> > >
> > > Bojan
> >
> > That explains it.
> >
> > Tomcat doesn't dump that classloader on a reload.
> >
> > It *only* dumps WEB-INF/lib and WEB-INF/classes
> >
> > -jon
> 
> I wasn't really expecting that the lib/apps would get dumped. My
> question is more along the lines of the VelocitEngine.init() not
> reporting creation of parsers etc. I'm calling init() on a brand new
> VelocityEngine object, so unless init stuff was cached somewhere...
> 
> Bojan

Just had a peek into Velocity code...

VelocityEngine creates a RuntimeInstance object and stores it into a
private class variable. When VelocityEngine's init runs, it just calls
RuntimeInstance's init, which checks the initialized boolean variable
(also private class variable) and if that's false (which should be for a
brand new object, right?), it should print out 'RuntimeInstance v1.2x
initializing' and so on.

How come I don't have that in the log files every time
VelocityEngine.init() gets executed? Or better still, maybe the thing
doesn't get executed although Tomcat says it does...

That's what's confusing me. I don't think that would have to do with
classloaders at all.

Bojan

Bojan

Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
"Geir Magnusson Jr." wrote:
> 
> On 9/9/01 12:00 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> 
> > Jon Stevens wrote:
> >>
> >> on 9/9/01 2:44 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> >>
> >>> Jon Stevens wrote:
> >>>>
> >>>> on 9/9/01 2:39 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> >>>>
> >>>>> Velocity, however, doesn't report a reload (I'm using non-singleton
> >>>>> model), although I have this in the servlet init():
> >>>>>
> >>>>> ----------------------------------------
> >>>>> /* Initialise Velocity */
> >>>>> ve=new VelocityEngine();
> >>>>> ve.init(p);
> >>>>> ----------------------------------------
> >>>>>
> >>>>> and Tomcat reports that the init of the servlet was executed. A bit
> >>>>> confusing...
> >>>>>
> >>>>> Bojan
> >>>>
> >>>> Where is your velocity.jar?
> >>>>
> >>>> -jon
> >>>
> >>> In Tomcat's lib/apps directory.
> >>>
> >>> Bojan
> >>
> >> That explains it.
> >>
> >> Tomcat doesn't dump that classloader on a reload.
> >>
> >> It *only* dumps WEB-INF/lib and WEB-INF/classes
> >>
> >> -jon
> >
> > I wasn't really expecting that the lib/apps would get dumped. My
> > question is more along the lines of the VelocitEngine.init() not
> > reporting creation of parsers etc. I'm calling init() on a brand new
> > VelocityEngine object, so unless init stuff was cached somewhere...
> >
> 
> It was a brand new VelocityEngine?  Not from VelocityServlet, using the
> singleton?

I'm using my own servlet (PumpServlet) which is not based on
VelocityServlet. The init method of the servlet creates a new
VelocityEngine object and stores it into a private class variable for
future use.

The confusing part is that Tomcat reports this after one of the classes
get refreshed:

----------------------------------------------------------
==> /var/tomcat/logs/servlet.log <==
2001-09-10 07:27:19 - www.binarix.dev:: pump: destroy
2001-09-10 07:27:19 - www.binarix.dev:: pump: init
----------------------------------------------------------

Destroy/init cycle of the servlet...

----------------------------------------------------------
==> /var/tomcat/logs/tomcat_error.log <==
2001-09-10 07:27:19 - ContextManager: Removing context
www.binarix.dev:/ROOT
2001-09-10 07:27:19 - Ctx() : Remove mapping 
2001-09-10 07:27:19 - ContextManager: Adding context
www.binarix.dev:/ROOT
Just initialised...
----------------------------------------------------------

Context removal/addition and then one of my beans prints 'Just
initialised...'. But although servlet's init was called, which creates
brand new VelocityEngine object and then calls its init (as per code
snippet before), Velocity doesn't report anything special apart from:

----------------------------------------------------------
==> /var/tomcat/logs/velocity.log <==
Mon Sep 10 07:27:29 EST 2001   [info] Velocimacro : added new VM :
#input( element ) : source = /edit.vm
Mon Sep 10 07:27:29 EST 2001   [info] Velocimacro : added new VM :
#textarea( element ) : source = /edit.vm
Mon Sep 10 07:27:29 EST 2001   [info] Velocimacro : added new VM :
#member( element ) : source = /edit.vm
Mon Sep 10 07:27:29 EST 2001   [info] Velocimacro : added new VM :
#text( element ) : source = /edit.vm
Mon Sep 10 07:27:29 EST 2001   [info] Velocimacro : added new VM :
#image( element ) : source = /edit.vm
Mon Sep 10 07:27:29 EST 2001   [info] Velocimacro : added new VM :
#anchor( element ) : source = /edit.vm
Mon Sep 10 07:27:29 EST 2001   [info] Velocimacro : added new VM :
#heading( element ) : source = /edit.vm
Mon Sep 10 07:27:29 EST 2001   [info] Velocimacro : added new VM :
#element( element ) : source = /edit.vm
Mon Sep 10 07:27:29 EST 2001   [info] Velocimacro : added new VM :
#elements( element ) : source = /edit.vm
Mon Sep 10 07:27:29 EST 2001   [info] ResourceManager : found /edit.vm
with loader
org.apache.velocity.runtime.resource.loader.FileResourceLoader
----------------------------------------------------------

which is just from one of the templates.

Don't get me wrong, everything works fine, it's just that it's somewhat
confusing.

Bojan

Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
"Geir Magnusson Jr." wrote:
> 
> On 9/9/01 6:15 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> >
> > You are right about Velocity 1.2-dev in lib/apps. Introspector would
> > cause leaks for sure, since it wouldn't get dumped when a class from
> > within an app has changed. So, some sort of cleanup is warranted.
> 
> Cleanup is coming...

Thx mate!

> >> BTW, I do NOT agree on using a String (class name) as a key for the
> >> Introspection Cache. But I will try to move that to the "dev" list.
> >
> > I prefer to watch this one from the sidelines as I don't know enough to
> > comment. Will be more than happy to test and provide feedback though.
> 
> And test you will...

I have my finger ready on jakarta-cvs script...

Bojan

Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/9/01 6:15 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> 
> You are right about Velocity 1.2-dev in lib/apps. Introspector would
> cause leaks for sure, since it wouldn't get dumped when a class from
> within an app has changed. So, some sort of cleanup is warranted.

Cleanup is coming...
 
>> BTW, I do NOT agree on using a String (class name) as a key for the
>> Introspection Cache. But I will try to move that to the "dev" list.
> 
> I prefer to watch this one from the sidelines as I don't know enough to
> comment. Will be more than happy to test and provide feedback though.

And test you will...

Geir

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
Paulo Gaspar wrote:

> Still, the Introspector cache must cause a huge memory leak when you
> place the Velocity jar in lib/apps and reload applications: Any classes
> that are introspected (and cached) will not be GCed even after their
> WebApp is stopped. And to make it worse, that means that their Class
> Loader will also not be GCed together with any static objects that loaded
> by that same CL.

It is funny how every discussion helps you see things in a totally
different light... As ESR points out: "Given enough eye balls, all bugs
are shallow".

When I had Velocity 1.1 in WEB-INF/lib of each app, I was seeing memory
leaks and I thought that was caused by Introspector holding references,
just like Attila pointed out. But, if a class was changed within that
web app, Tomcat would dump the whole thing and reload everything from
scratch, including the singleton of Velocity and the Introspector. So,
if that's the case, that couldn't have caused the memory leak because
everything was reloaded and garbage was properly collected. Right?

Now I'm seriously confused :-(

The only explanation (in relation to Introspector) for the above leaks
is the fact that I have my own properties files and when they change, my
servlet loads new beans into the ServletContext and HttpSession. Since
Tomcat's classloader isn't dumping the app here, the Introspector could
be involved because it would cache the previous methods etc.

You are right about Velocity 1.2-dev in lib/apps. Introspector would
cause leaks for sure, since it wouldn't get dumped when a class from
within an app has changed. So, some sort of cleanup is warranted.

> BTW, I do NOT agree on using a String (class name) as a key for the
> Introspection Cache. But I will try to move that to the "dev" list.

I prefer to watch this one from the sidelines as I don't know enough to
comment. Will be more than happy to test and provide feedback though.

Bojan

Re: suggestion: use WeakHashMap to implement the introspection cache

Posted by Attila Szegedi <sz...@freemail.hu>.
I'll take a look at that, it seems intriguing. Thanks for the link.
Meanwhile, we have dropped the idea of using weak references in favor of a
heuristic that detects class reloads when it sees two different class
objects with the same qualified name.

Attila.


----- Original Message -----
From: "Lane Sharman" <la...@san.rr.com>
To: <ve...@jakarta.apache.org>
Sent: 2001. szeptember 11. 1:14
Subject: Re: suggestion: use WeakHashMap to implement the introspection
cache


> Attila Szegedi wrote:
>
> > EAlso, when you do a lookup in WeakHashMap (containsKey, get, remove) it
will
> >
> > create a new, temporary WeakReference for purposes of comparing it to
other
> > keys (which are also WeakReferences). This can take time. Also, each
method
> > calls a reference queue processor loop that removes entries with cleared
> > references from the map, also adding to the overhead.
>
> Be sure to benchmark a caching provider that holds elements for shared
access.
> My tests found Weak/Soft references to add an unacceptable cost to overall
> throughput. The thread which does the remove has to be synchronized with
the
> thread doing the get().
>
> I implemented a generational caching provider. There is no contention or
> synchronization because mutations are done to a provisional generation
which
> becomes the working generation on a periodic basis AND when there is
longish
> period of cache idelness. http://engineering.acctiva.org/vfc for details
on a
> generational cache manager.
>
> -lane
>
>


Re: suggestion: use WeakHashMap to implement the introspection cache

Posted by Lane Sharman <la...@san.rr.com>.
Attila Szegedi wrote:

> EAlso, when you do a lookup in WeakHashMap (containsKey, get, remove) it will
>
> create a new, temporary WeakReference for purposes of comparing it to other
> keys (which are also WeakReferences). This can take time. Also, each method
> calls a reference queue processor loop that removes entries with cleared
> references from the map, also adding to the overhead.

Be sure to benchmark a caching provider that holds elements for shared access.
My tests found Weak/Soft references to add an unacceptable cost to overall
throughput. The thread which does the remove has to be synchronized with the
thread doing the get().

I implemented a generational caching provider. There is no contention or
synchronization because mutations are done to a provisional generation which
becomes the working generation on a periodic basis AND when there is longish
period of cache idelness. http://engineering.acctiva.org/vfc for details on a
generational cache manager.

-lane


Re: suggestion: use WeakHashMap to implement the introspection cache

Posted by Attila Szegedi <sz...@freemail.hu>.
Each time you store something in a WeakHashMap, you'll create another
WeakReference. It's an object, and it takes up space. If I remembered
correctly, each reference object has 3 fields (one for referred object, for
reference queue, and for next reference in the queue) so it takes at least
12 bytes of storage + storage required for java.lang.Object.

Also, when you do a lookup in WeakHashMap (containsKey, get, remove) it will
create a new, temporary WeakReference for purposes of comparing it to other
keys (which are also WeakReferences). This can take time. Also, each method
calls a reference queue processor loop that removes entries with cleared
references from the map, also adding to the overhead.

Attila.

----- Original Message -----
From: "Mike Williams" <md...@users.sourceforge.net>
To: <ve...@jakarta.apache.org>
Sent: Tuesday, September 11, 2001 12:25 AM
Subject: Re: suggestion: use WeakHashMap to implement the introspection
cache


>   Mike> You guys thought about using java.util.WeakHashMap to implement
the
>   Mike> introspection caches?
>
>   Geir> Read back.  That was Attila's first suggestion,
>
> Whoops ... sorry.
>
>   Geir> but if you read along, a scheme was cooked up that avoids it.
>
> Okay, so now you're discarding the cache whenever there's a class re-load,
> right?
>
>   Attila> It is somewhat worse than using weak references [...] however it
>   Attila> has the advantage of having no negative memory or performance
>   Attila> impact on behalf of Introspector.
>
> Just out of interest, what's the negative memory/performance impact of the
> WeakHashMap approach?
>
> --
> cheers, Mike
>
>


Re: suggestion: use WeakHashMap to implement the introspection cache

Posted by Mike Williams <md...@users.sourceforge.net>.
  Mike> You guys thought about using java.util.WeakHashMap to implement the
  Mike> introspection caches?

  Geir> Read back.  That was Attila's first suggestion, 

Whoops ... sorry.

  Geir> but if you read along, a scheme was cooked up that avoids it.

Okay, so now you're discarding the cache whenever there's a class re-load,
right?

  Attila> It is somewhat worse than using weak references [...] however it
  Attila> has the advantage of having no negative memory or performance
  Attila> impact on behalf of Introspector.

Just out of interest, what's the negative memory/performance impact of the
WeakHashMap approach?

-- 
cheers, Mike


Re: suggestion: use WeakHashMap to implement the introspection cache

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/10/01 12:06 AM, "Mike Williams" <md...@users.sourceforge.net> wrote:

>>>> On Mon, 10 Sep 2001 05:11:18 +0200,
>>>> "Paulo" == "Paulo Gaspar" <pa...@krankikom.de> wrote:
> 
> Paulo> Still, the Introspector cache must cause a huge memory leak when you
> Paulo> place the Velocity jar in lib/apps and reload applications: Any classes
> Paulo> that are introspected (and cached) will not be GCed even after their
> Paulo> WebApp is stopped. And to make it worse, that means that their Class
> Paulo> Loader will also not be GCed together with any static objects that
> loaded
> Paulo> by that same CL.
> 
> You guys thought about using java.util.WeakHashMap to implement the
> introspection caches?
> 
>   A hashtable-based Map implementation with weak keys. An entry in a
>   WeakHashMap will automatically be removed when its key is no longer in
>   ordinary use. More precisely, the presence of a mapping for a given key
>   will not prevent the key from being discarded by the garbage collector,
>   that is, made finalizable, finalized, and then reclaimed. When a key
>   has been discarded its entry is effectively removed from the map ...

:)

Read back.  That was Attila's first suggestion, but if you read along, a
scheme was cooked up that avoids it.

Will be checked in in a moment...

geir

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


suggestion: use WeakHashMap to implement the introspection cache

Posted by Mike Williams <md...@users.sourceforge.net>.
  >>> On Mon, 10 Sep 2001 05:11:18 +0200,
  >>> "Paulo" == "Paulo Gaspar" <pa...@krankikom.de> wrote:

  Paulo> Still, the Introspector cache must cause a huge memory leak when you 
  Paulo> place the Velocity jar in lib/apps and reload applications: Any classes
  Paulo> that are introspected (and cached) will not be GCed even after their 
  Paulo> WebApp is stopped. And to make it worse, that means that their Class 
  Paulo> Loader will also not be GCed together with any static objects that loaded
  Paulo> by that same CL.

You guys thought about using java.util.WeakHashMap to implement the
introspection caches?

    A hashtable-based Map implementation with weak keys. An entry in a
    WeakHashMap will automatically be removed when its key is no longer in
    ordinary use. More precisely, the presence of a mapping for a given key
    will not prevent the key from being discarded by the garbage collector,
    that is, made finalizable, finalized, and then reclaimed. When a key
    has been discarded its entry is effectively removed from the map ...

-- 
cheers, Mike

"Life is like an analogy."


RE: performance questions

Posted by Paulo Gaspar <pa...@krankikom.de>.
Sorry Bojan, you are clearly ahead of what I was understanding from a 
paragraph you wrote in a previous posting:
> How come I don't have that in the log files every time
> VelocityEngine.init() gets executed? Or better still, maybe the thing
> doesn't get executed although Tomcat says it does...

My bad, since I did not notice the "VelocityEngine" (which, of course, is 
not a singleton).

Still, the Introspector cache must cause a huge memory leak when you 
place the Velocity jar in lib/apps and reload applications: Any classes
that are introspected (and cached) will not be GCed even after their 
WebApp is stopped. And to make it worse, that means that their Class 
Loader will also not be GCed together with any static objects that loaded
by that same CL.


BTW, I do NOT agree on using a String (class name) as a key for the 
Introspection Cache. But I will try to move that to the "dev" list.


Have fun,
Paulo Gaspar


> -----Original Message-----
> From: bojan@binarix.com [mailto:bojan@binarix.com]
> Sent: Monday, September 10, 2001 4:43 AM
> To: velocity-user@jakarta.apache.org
> Subject: Re: performance questions
> 
> 
> Paulo Gaspar wrote:
> 
> > That is why Bojan must have had a load of trouble with his Velocity jar
> > placed at Tomcat's "lib/apps" directory. Jars in that directory are
> > loaded by a CL which is parent (or an ancestor) to the CLs of all the
> > WebApps. In this situation one can end up with Velocity loaded once for
> > many WebApps... but that also means that the Singletons (and all static
> > stuff) are also common to all WebApps... and that means a lot of nasty
> > side effects, including that the loaded configuration would be a bit
> > random (depending on which Servlet did it first (or last?)) and common
> > to all those WebApps - probably not what you usually want.
> 
> I use non-singleton model from Velocity 1.2-dev. I'm aware of previous
> singleton behaviour in 1.1 and earlier and I used to have velocity*.jar
> in WEB-INF/lib as per Velocity documentation. There is no need for that
> with Velocity 1.2-dev, provided the new non-singleton model is used. The
> configuration properties are passed to VelocityEngine.init() method when
> new instance is created, so it is not random at all. Actually, I have
> about 10 apps using different configuration with the same velocity*.jar
> file in lib/apps. And they all work just fine.
> 
> There is actually no trouble with Velocity 1.2-dev in lib/apps of
> Tomcat. Apart from other outstanding Velocity issues, that is. One of
> those issues is the potential memory leak caused by the Introspector.
> 
> Bojan
> 

Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
Paulo Gaspar wrote:

> That is why Bojan must have had a load of trouble with his Velocity jar
> placed at Tomcat's "lib/apps" directory. Jars in that directory are
> loaded by a CL which is parent (or an ancestor) to the CLs of all the
> WebApps. In this situation one can end up with Velocity loaded once for
> many WebApps... but that also means that the Singletons (and all static
> stuff) are also common to all WebApps... and that means a lot of nasty
> side effects, including that the loaded configuration would be a bit
> random (depending on which Servlet did it first (or last?)) and common
> to all those WebApps - probably not what you usually want.

I use non-singleton model from Velocity 1.2-dev. I'm aware of previous
singleton behaviour in 1.1 and earlier and I used to have velocity*.jar
in WEB-INF/lib as per Velocity documentation. There is no need for that
with Velocity 1.2-dev, provided the new non-singleton model is used. The
configuration properties are passed to VelocityEngine.init() method when
new instance is created, so it is not random at all. Actually, I have
about 10 apps using different configuration with the same velocity*.jar
file in lib/apps. And they all work just fine.

There is actually no trouble with Velocity 1.2-dev in lib/apps of
Tomcat. Apart from other outstanding Velocity issues, that is. One of
those issues is the potential memory leak caused by the Introspector.

Bojan

RE: performance questions

Posted by Paulo Gaspar <pa...@krankikom.de>.
As far as I understand it, the Class Loader (CL) does not get instantly
nullified (but then I could be wrong).

A class in (loaded by) a given CL has access to all the classes loaded
by that CL and by the parent/ancestors CLs of that CL. But it has no
access to a class loaded by a sibling CL!

A CL is kept existing just as any Java class: because there is a
reference to it. When no reference exists neither to a given CL "X" nor
to the objects and classes loaded by that CL "X" from objects loaded by
other CLs, then both CL "X" and its universe of objects/classes are
material for garbage collection (GC).


In the case of Tomcat:
    A given Web Application (WebApp) - including its CL, its servlets
    and any other classes and objects it loads - its kept active because
    the Tomcat keeps references to its CL and to (in a simplistic way)
    its servlets.

    (In a not so simplistic way, I think that Tomcat keeps reference
    to a WebApp Context object which is the one keeping references to
    Servlets and other WebApp objects.)

    Tomcat removes that web application just by removing all those
    references both to the CL and those Servlets (or those other WebApp
    objects). Since there are no more references to those objects and
    its CL, they just become GC material. When the CL is GCed, all
    singletons (static objects) of the classes it loaded are GCed too.


Also, AFAIK, singletons and other static objects "belong" to the CL
that loaded its class.

That is why Bojan must have had a load of trouble with his Velocity jar
placed at Tomcat's "lib/apps" directory. Jars in that directory are
loaded by a CL which is parent (or an ancestor) to the CLs of all the
WebApps. In this situation one can end up with Velocity loaded once for
many WebApps... but that also means that the Singletons (and all static
stuff) are also common to all WebApps... and that means a lot of nasty
side effects, including that the loaded configuration would be a bit
random (depending on which Servlet did it first (or last?)) and common
to all those WebApps - probably not what you usually want.


This is also the problem with libraries that depend on Singletons. I
used to be a Singleton enthusiast when I was building DOS (I feel old
when I mention this) and Windows apps... but in the world of WebApps
and multiple CLs, that does not look like such a smart idea anymore.

In my own libraries I only put in a static variable what can really
be common to ANYTHING that uses the damn library.

That is why I liked it so much when Geir introduced multiple instance.
Now I just pray that some day we get though and start deprecating
singletons.


I hope I will be able to contribute more than words to that. I have
an idea about how to make Velocity simpler and more flexible in a way
that would also make it easier to have multiple applications (from
multiple class loaders) sharing it.

I already talked about some of its principles some weeks ago, but it
demands a lot of work and I am really busy with something else.

Anyway, this "something else" also needs a better Velocity - although,
by now, it can survive with the Multiple Instance thing (thanks a lot
Geir) - so I hope I will have to get back to this.

Yes, lots of intentions and not so much actions just yet.
(o;=


Have fun,
Paulo Gaspar



> -----Original Message-----
> From: Jon Stevens [mailto:jon@latchkey.com]
> Sent: Monday, September 10, 2001 1:55 AM
> To: velocity-user
> Subject: Re: performance questions
>
>
> on 9/9/01 4:38 PM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:
>
> > On 9/9/01 12:36 PM, "Paulo Gaspar" <pa...@krankikom.de> wrote:
> >
> >> According to the Java spec (yes, I was really reading the class loading
> >> part a couple of weeks ago) it is JUST like Jon says.
> >>
> >> Which in turn means: it does not matter if it is a singleton or not.
> >>
> >> A different class loader is a bit like a different universe, unless one
> >> is parent/ancestor of the other.
> >
> > So you have some singleton instance of something that is
> happily off doing
> > work, say with a few threads...
> >
> > Then you dump the classloader that created it.
> >
> > The JVM then instantly destroy's every object created by that
> classloader??
> >
> > Yikes.
> >
> > How do you catch this to do cleanup?
>
> Implement:
>
>     public void destroy()
>     {
>     }
>
> > I believe you all, but first, it goes against my (broken)
> mental model which
> > I will fix :) , and two, it's horribly frightening to think that in the
> > normal course of business, a living object gets automatically destroyed
> > arbitrarily because the classloader changed.
>
> The CL doesn't get 'changed', it gets nullified and a new one is
> created to
> replace the previous one. :-) It is then the new CL's job to load whatever
> classes it is requested to load. CL's also don't cache the
> instances to the
> objects...instead...
>
> The issue is that each Object has an internal reference to the CL that
> created it. If that CL becomes invalid, then you get all sorts of nasty
> exceptions if you try to use that Object in any way.
>
> Therefore, you must make certain that access to ALL of those
> Objects is not
> given. You also have to make sure that each of those objects is removed in
> order to remove all references to the previous CL in order to
> allow for that
> CL to get GC'd.
>
> > I guess you have to be really
> > careful with classloader interaction in critical systems.
>
> Without a doubt.
>
> CL's are one of the most important, most complex, least
> understood and most
> poorly designed parts of the Java Language. :-)
>
> -jon
>


Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
Attila Szegedi wrote:

> A singleton is a singleton in class loader scope, not in VM scope. 

I think I'm starting to understand now what Jon meant with
SingleThreadModel in Servlet API in relation to static fields. But if
that was the case (each servlet instance was a true singleton), wouldn't
every one of those had to have a separate classloader?

Bojan

PS. I was just wondering how much would a Java course like this cost out
there in the open ;-)

Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/9/01 10:08 PM, "Attila Szegedi" <sz...@freemail.hu> wrote:

> 
> ----- Original Message -----
> From: "Geir Magnusson Jr." <ge...@optonline.net>
> To: <ve...@jakarta.apache.org>
> Sent: 2001. szeptember 10. 8:11
> Subject: Re: performance questions
> 
> 
> <snip/>
>> 
>> So how does it work for singletons?  I assume that the classloader then
> has
>> to keep the reference, and if that singleton is doing work (oh, say,
>> controlling the flaps on a landing :), then something special has to be
> done
>> rather than just punting and letting it get GC'd, as you don't want two of
>> those flap-controlling singletons working at the same time...
>> 
> 
> A singleton is a singleton in class loader scope, not in VM scope. You can
> have the same class loaded by two distinct class loaders, and from the VM
> standpoint these are *two different classes*, each having a distinct set of
> static fields. To ensure a class is VM-wide singleton, you must load it
> through some "global" class loader: boot, ext, or app class loader. (If I
> wanted to split hairs, then I'd say only stuff loaded through boot class
> loader is VM-wide singleton, since what is loaded through ext is not
> accessible to boot, and what is loaded through app is not accessible to both
> ext and boot, so they're not actually VM-wide in the strictest sense.)
> Class loaders form a hierarchy (with boot being the ultimate root), and the
> loader closest to the root that finds the class loads it and propagates it
> to its subordinate class loaders. That's why Velocity in lib/apps is a
> singleton to all web applications: Tomcat is engineered in such a manner
> that webapp class loaders are subordinate to the class loader that loads
> from lib/apps, so they'll share all classes loaded from lib/apps.
> 
> I can unserstand if you're feeling uneasy with the possibility of having
> multiple singletons.

No, I don't mind - as I do it all the time in separate webapps using the old
Singleton model for Velocity.  I guess now that I just said that, it had to
be the classloader that managed the reference to the singleton instance, so
indeed, letting that CL get GC'd implies the singleton is a goner as well...

Thx

geir

> I did too, but as I gave it more thought I understood
> that this feature provides for very good isolation of independent subsystems
> (i.e. multiple webapps) inside a single VM. In most cases, it's no problem
> if you have multiple singletons, as they're quite isolated. The problem is
> if they manage shared external state (say, a table in a RDBMS) - you really
> cannot assume there will be only one in the VM process, so even with
> singletons you must prepare for concurrent access.
> 
> Attila.
> 
> 
> 

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Attila Szegedi <sz...@freemail.hu>.
----- Original Message -----
From: "Geir Magnusson Jr." <ge...@optonline.net>
To: <ve...@jakarta.apache.org>
Sent: 2001. szeptember 10. 8:11
Subject: Re: performance questions


<snip/>
>
> So how does it work for singletons?  I assume that the classloader then
has
> to keep the reference, and if that singleton is doing work (oh, say,
> controlling the flaps on a landing :), then something special has to be
done
> rather than just punting and letting it get GC'd, as you don't want two of
> those flap-controlling singletons working at the same time...
>

A singleton is a singleton in class loader scope, not in VM scope. You can
have the same class loaded by two distinct class loaders, and from the VM
standpoint these are *two different classes*, each having a distinct set of
static fields. To ensure a class is VM-wide singleton, you must load it
through some "global" class loader: boot, ext, or app class loader. (If I
wanted to split hairs, then I'd say only stuff loaded through boot class
loader is VM-wide singleton, since what is loaded through ext is not
accessible to boot, and what is loaded through app is not accessible to both
ext and boot, so they're not actually VM-wide in the strictest sense.)
Class loaders form a hierarchy (with boot being the ultimate root), and the
loader closest to the root that finds the class loads it and propagates it
to its subordinate class loaders. That's why Velocity in lib/apps is a
singleton to all web applications: Tomcat is engineered in such a manner
that webapp class loaders are subordinate to the class loader that loads
from lib/apps, so they'll share all classes loaded from lib/apps.

I can unserstand if you're feeling uneasy with the possibility of having
multiple singletons. I did too, but as I gave it more thought I understood
that this feature provides for very good isolation of independent subsystems
(i.e. multiple webapps) inside a single VM. In most cases, it's no problem
if you have multiple singletons, as they're quite isolated. The problem is
if they manage shared external state (say, a table in a RDBMS) - you really
cannot assume there will be only one in the VM process, so even with
singletons you must prepare for concurrent access.

Attila.




Re: performance questions

Posted by Attila Szegedi <sz...@freemail.hu>.
----- Original Message -----
From: "Jon Stevens" <jo...@latchkey.com>
To: "velocity-user" <ve...@jakarta.apache.org>
Sent: 2001. szeptember 10. 8:27
Subject: Re: performance questions


> on 9/9/01 11:11 PM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:
>
<snip/>
>
> > I assume that the classloader then has
> > to keep the reference, and if that singleton is doing work (oh, say,
> > controlling the flaps on a landing :), then something special has to be
done
> > rather than just punting and letting it get GC'd, as you don't want two
of
> > those flap-controlling singletons working at the same time...
>
> No. The CL doesn't keep references to objects. The objects themselves keep
> references to the CL.
>

I guess what confuses Geir is that how does then a CL keep a singleton
instance loaded.
It's like this:
- a CL keeps a strong reference to every class it loads (it has to, since if
it didn't then a Class.forName("com.foo.Blah") !=
Class.forName("com.foo.Blah") could actually happen if the class were GC-ed
and reloaded between evaluation of left and right hand side of the
expression)
- a class keeps a strong reference to its singleton, tipically in a static
field.

Attila.





Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
Jon Stevens wrote:
> 
> on 9/10/01 12:14 AM, "Bojan Smojver" <bo...@binarix.com> wrote:
> 
> > I guess one of the wonders that comes with containers. As long as people
> > understand how it really works...
> 
> There is nothing in the spec that says that containers can't do that. :-)

Interesting. So there is a way to make static fields non-static after
the class was compiled? Or do you do that at load time? Wouldn't that be
even more confusing as it would step away from normal Java behaviour?
I'm not sure I quite follow what you meant here...

> > Seriously, was a better concept ever tossed around?
> 
> A better concept for STM? No. The idea is that threaded programming isn't
> that hard. I wonder how many JSP's have MT threading issues. :-)

I can tell you one thing for sure: in all my web apps the percentage of
JSP with threading issues is decreasing daily and at great velocity :-)

Bojan

Re: performance questions

Posted by Jon Stevens <jo...@latchkey.com>.
on 9/10/01 12:14 AM, "Bojan Smojver" <bo...@binarix.com> wrote:

> I guess one of the wonders that comes with containers. As long as people
> understand how it really works...

There is nothing in the spec that says that containers can't do that. :-)

> Seriously, was a better concept ever tossed around?

A better concept for STM? No. The idea is that threaded programming isn't
that hard. I wonder how many JSP's have MT threading issues. :-)

-jon


Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
Jon Stevens wrote:

> It is possible to make many instantiations of the same object and hold onto
> them (thus making them singletons). This is exactly what the
> SingleThreadModel in the Servlet spec is and why STM sucks so badly. :-)
> Jserv would create multiple instances of a STM servlet and then dole them
> out one at a time. However, if those instances had static fields within
> them, they could be overwritten by other instances of the STM that get
> executed and if it depends on it being one value, then it could really mess
> up others that expect another value. Oy, not what people were expecting eh?
> :-)

I guess one of the wonders that comes with containers. As long as people
understand how it really works...

This is similar to EJB's where use of static fields is prohibited (or
discouraged, not 100% on that one) unless they are final. At least
stateful session beans can keep the stuff for you, along the lines of
HttpSession but without the hassles of getting the session and its
attributes. I wonder if one could write a web server using EJB's? I know
you like those, so maybe we can start a project like that ;-)

Seriously, was a better concept ever tossed around?

Bojan

Re: performance questions

Posted by Jon Stevens <jo...@latchkey.com>.
on 9/9/01 11:11 PM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:

> So how does it work for singletons?

Reminder definition: All a singleton is is an object which has been
instantiated (by a classloader) and then a reference is held on to the
object.

> I assume that the classloader then has
> to keep the reference, and if that singleton is doing work (oh, say,
> controlling the flaps on a landing :), then something special has to be done
> rather than just punting and letting it get GC'd, as you don't want two of
> those flap-controlling singletons working at the same time...

No. The CL doesn't keep references to objects. The objects themselves keep
references to the CL.

It is possible to make many instantiations of the same object and hold onto
them (thus making them singletons). This is exactly what the
SingleThreadModel in the Servlet spec is and why STM sucks so badly. :-)
Jserv would create multiple instances of a STM servlet and then dole them
out one at a time. However, if those instances had static fields within
them, they could be overwritten by other instances of the STM that get
executed and if it depends on it being one value, then it could really mess
up others that expect another value. Oy, not what people were expecting eh?
:-)

> I am starting to think +1 on that 'poorly designed' bit...  Maybe, to be
> generous, we can say 'horribly abused'...

Well, if it wasn't so poorly designed, it wouldn't get so horribly abused.
:-) Kind of like JSP.

-jon


Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/9/01 1:54 PM, "Jon Stevens" <jo...@latchkey.com> wrote:

> on 9/9/01 4:38 PM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:
> 
>> On 9/9/01 12:36 PM, "Paulo Gaspar" <pa...@krankikom.de> wrote:
>> 
>>> According to the Java spec (yes, I was really reading the class loading
>>> part a couple of weeks ago) it is JUST like Jon says.
>>> 
>>> Which in turn means: it does not matter if it is a singleton or not.
>>> 
>>> A different class loader is a bit like a different universe, unless one
>>> is parent/ancestor of the other.
>> 
>> So you have some singleton instance of something that is happily off doing
>> work, say with a few threads...
>> 
>> Then you dump the classloader that created it.
>> 
>> The JVM then instantly destroy's every object created by that classloader??
>> 
>> Yikes.
>> 
>> How do you catch this to do cleanup?
> 
> Implement:
> 
>   public void destroy()
>   {
>   }
> 
>> I believe you all, but first, it goes against my (broken) mental model which
>> I will fix :) , and two, it's horribly frightening to think that in the
>> normal course of business, a living object gets automatically destroyed
>> arbitrarily because the classloader changed.
> 
> The CL doesn't get 'changed', it gets nullified and a new one is created to
> replace the previous one. :-)

Obviously not 'changed', like it wet itself or something... :)


> It is then the new CL's job to load whatever
> classes it is requested to load. CL's also don't cache the instances to the
> objects...instead...
> 
> The issue is that each Object has an internal reference to the CL that
> created it. If that CL becomes invalid, then you get all sorts of nasty
> exceptions if you try to use that Object in any way.
> 
> Therefore, you must make certain that access to ALL of those Objects is not
> given. You also have to make sure that each of those objects is removed in
> order to remove all references to the previous CL in order to allow for that
> CL to get GC'd.

So how does it work for singletons?  I assume that the classloader then has
to keep the reference, and if that singleton is doing work (oh, say,
controlling the flaps on a landing :), then something special has to be done
rather than just punting and letting it get GC'd, as you don't want two of
those flap-controlling singletons working at the same time...
   
>> I guess you have to be really
>> careful with classloader interaction in critical systems.
> 
> Without a doubt.
> 
> CL's are one of the most important, most complex, least understood and most
> poorly designed parts of the Java Language. :-)

I am starting to think +1 on that 'poorly designed' bit...  Maybe, to be
generous, we can say 'horribly abused'...

geir

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Jon Stevens <jo...@latchkey.com>.
on 9/9/01 4:38 PM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:

> On 9/9/01 12:36 PM, "Paulo Gaspar" <pa...@krankikom.de> wrote:
> 
>> According to the Java spec (yes, I was really reading the class loading
>> part a couple of weeks ago) it is JUST like Jon says.
>> 
>> Which in turn means: it does not matter if it is a singleton or not.
>> 
>> A different class loader is a bit like a different universe, unless one
>> is parent/ancestor of the other.
> 
> So you have some singleton instance of something that is happily off doing
> work, say with a few threads...
> 
> Then you dump the classloader that created it.
> 
> The JVM then instantly destroy's every object created by that classloader??
> 
> Yikes.
> 
> How do you catch this to do cleanup?

Implement:

    public void destroy()
    {
    }

> I believe you all, but first, it goes against my (broken) mental model which
> I will fix :) , and two, it's horribly frightening to think that in the
> normal course of business, a living object gets automatically destroyed
> arbitrarily because the classloader changed.

The CL doesn't get 'changed', it gets nullified and a new one is created to
replace the previous one. :-) It is then the new CL's job to load whatever
classes it is requested to load. CL's also don't cache the instances to the
objects...instead...

The issue is that each Object has an internal reference to the CL that
created it. If that CL becomes invalid, then you get all sorts of nasty
exceptions if you try to use that Object in any way.

Therefore, you must make certain that access to ALL of those Objects is not
given. You also have to make sure that each of those objects is removed in
order to remove all references to the previous CL in order to allow for that
CL to get GC'd.

> I guess you have to be really
> careful with classloader interaction in critical systems.

Without a doubt.

CL's are one of the most important, most complex, least understood and most
poorly designed parts of the Java Language. :-)

-jon


Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/9/01 12:36 PM, "Paulo Gaspar" <pa...@krankikom.de> wrote:

> According to the Java spec (yes, I was really reading the class loading
> part a couple of weeks ago) it is JUST like Jon says.
> 
> Which in turn means: it does not matter if it is a singleton or not.
> 
> A different class loader is a bit like a different universe, unless one
> is parent/ancestor of the other.

So you have some singleton instance of something that is happily off doing
work, say with a few threads...

Then you dump the classloader that created it.

The JVM then instantly destroy's every object created by that classloader??

Yikes.

How do you catch this to do cleanup?
 
> 
> Have fun,
> Paulo Gaspar
> 
> P.S.: See? I can COMPLETELY agree with Jon... sometimes!
> =;o)

It's not a matter of disagreeing with Jon - this is a factual issue where
there are no opinions that matter...

I believe you all, but first, it goes against my (broken) mental model which
I will fix :) , and two, it's horribly frightening to think that in the
normal course of business, a living object gets automatically destroyed
arbitrarily because the classloader changed.  I guess you have to be really
careful with classloader interaction in critical systems.

geir

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


RE: performance questions

Posted by Paulo Gaspar <pa...@krankikom.de>.
According to the Java spec (yes, I was really reading the class loading 
part a couple of weeks ago) it is JUST like Jon says.

Which in turn means: it does not matter if it is a singleton or not.

A different class loader is a bit like a different universe, unless one
is parent/ancestor of the other.


Have fun,
Paulo Gaspar

P.S.: See? I can COMPLETELY agree with Jon... sometimes!
=;o)


> -----Original Message-----
> From: Geir Magnusson Jr. [mailto:geirm@optonline.net]
> Sent: Monday, September 10, 2001 12:01 AM
> To: velocity-user@jakarta.apache.org
> Subject: Re: performance questions
> 
> 
> It was a brand new VelocityEngine?  Not from VelocityServlet, using the
> singleton?
> 


Re: Classloaders...

Posted by Attila Szegedi <sz...@freemail.hu>.
Also, there's a GREAT article on class loaders titled "Java Statics (When a
static field really isn't static)" by a DevelopMentor instructor Ted Neward
reachable through site http://www.javageeks.com/tneward/index.html
The link appears broken right now, but I've alerted Ted to fix it.
What I know of class loaders comes mostly from this and other papers
referred on the above URL. Its concise, comprehensive, and to the point.

Attila.

----- Original Message -----
From: "Jon Stevens" <jo...@latchkey.com>
To: "velocity-user" <ve...@jakarta.apache.org>
Sent: 2001. szeptember 10. 0:19
Subject: Classloaders...


> Fyi...
>
>
<http://jakarta.apache.org/tomcat/tomcat-4.0-doc-exp/class-loader-howto.html
> >
>
> -jon
>
>


Classloaders...

Posted by Jon Stevens <jo...@latchkey.com>.
Fyi...

<http://jakarta.apache.org/tomcat/tomcat-4.0-doc-exp/class-loader-howto.html
>

-jon


Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/9/01 12:00 PM, "Bojan Smojver" <bo...@binarix.com> wrote:

> Jon Stevens wrote:
>> 
>> on 9/9/01 2:44 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
>> 
>>> Jon Stevens wrote:
>>>> 
>>>> on 9/9/01 2:39 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
>>>> 
>>>>> Velocity, however, doesn't report a reload (I'm using non-singleton
>>>>> model), although I have this in the servlet init():
>>>>> 
>>>>> ----------------------------------------
>>>>> /* Initialise Velocity */
>>>>> ve=new VelocityEngine();
>>>>> ve.init(p);
>>>>> ----------------------------------------
>>>>> 
>>>>> and Tomcat reports that the init of the servlet was executed. A bit
>>>>> confusing...
>>>>> 
>>>>> Bojan
>>>> 
>>>> Where is your velocity.jar?
>>>> 
>>>> -jon
>>> 
>>> In Tomcat's lib/apps directory.
>>> 
>>> Bojan
>> 
>> That explains it.
>> 
>> Tomcat doesn't dump that classloader on a reload.
>> 
>> It *only* dumps WEB-INF/lib and WEB-INF/classes
>> 
>> -jon
> 
> I wasn't really expecting that the lib/apps would get dumped. My
> question is more along the lines of the VelocitEngine.init() not
> reporting creation of parsers etc. I'm calling init() on a brand new
> VelocityEngine object, so unless init stuff was cached somewhere...
> 

It was a brand new VelocityEngine?  Not from VelocityServlet, using the
singleton?


-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
Jon Stevens wrote:
> 
> on 9/9/01 2:44 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> 
> > Jon Stevens wrote:
> >>
> >> on 9/9/01 2:39 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> >>
> >>> Velocity, however, doesn't report a reload (I'm using non-singleton
> >>> model), although I have this in the servlet init():
> >>>
> >>> ----------------------------------------
> >>> /* Initialise Velocity */
> >>> ve=new VelocityEngine();
> >>> ve.init(p);
> >>> ----------------------------------------
> >>>
> >>> and Tomcat reports that the init of the servlet was executed. A bit
> >>> confusing...
> >>>
> >>> Bojan
> >>
> >> Where is your velocity.jar?
> >>
> >> -jon
> >
> > In Tomcat's lib/apps directory.
> >
> > Bojan
> 
> That explains it.
> 
> Tomcat doesn't dump that classloader on a reload.
> 
> It *only* dumps WEB-INF/lib and WEB-INF/classes
> 
> -jon

I wasn't really expecting that the lib/apps would get dumped. My
question is more along the lines of the VelocitEngine.init() not
reporting creation of parsers etc. I'm calling init() on a brand new
VelocityEngine object, so unless init stuff was cached somewhere...

Bojan

Re: performance questions

Posted by Jon Stevens <jo...@latchkey.com>.
on 9/9/01 2:44 PM, "Bojan Smojver" <bo...@binarix.com> wrote:

> Jon Stevens wrote:
>> 
>> on 9/9/01 2:39 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
>> 
>>> Velocity, however, doesn't report a reload (I'm using non-singleton
>>> model), although I have this in the servlet init():
>>> 
>>> ----------------------------------------
>>> /* Initialise Velocity */
>>> ve=new VelocityEngine();
>>> ve.init(p);
>>> ----------------------------------------
>>> 
>>> and Tomcat reports that the init of the servlet was executed. A bit
>>> confusing...
>>> 
>>> Bojan
>> 
>> Where is your velocity.jar?
>> 
>> -jon
> 
> In Tomcat's lib/apps directory.
> 
> Bojan

That explains it.

Tomcat doesn't dump that classloader on a reload.

It *only* dumps WEB-INF/lib and WEB-INF/classes

-jon


Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
Jon Stevens wrote:
> 
> on 9/9/01 2:39 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> 
> > Velocity, however, doesn't report a reload (I'm using non-singleton
> > model), although I have this in the servlet init():
> >
> > ----------------------------------------
> > /* Initialise Velocity */
> > ve=new VelocityEngine();
> > ve.init(p);
> > ----------------------------------------
> >
> > and Tomcat reports that the init of the servlet was executed. A bit
> > confusing...
> >
> > Bojan
> 
> Where is your velocity.jar?
> 
> -jon

In Tomcat's lib/apps directory.

Bojan

Re: performance questions

Posted by Jon Stevens <jo...@latchkey.com>.
on 9/9/01 2:39 PM, "Bojan Smojver" <bo...@binarix.com> wrote:

> Velocity, however, doesn't report a reload (I'm using non-singleton
> model), although I have this in the servlet init():
> 
> ----------------------------------------
> /* Initialise Velocity */
> ve=new VelocityEngine();
> ve.init(p);
> ----------------------------------------
> 
> and Tomcat reports that the init of the servlet was executed. A bit
> confusing...
> 
> Bojan

Where is your velocity.jar?

-jon


Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
Attila Szegedi wrote:
> 
> Geir and I are now on a different track: essentially we'll assume in
> Introspector code that class reloading happened if introspection is
> requested for a class, and the Introspector detects it already has a
> *different* (probably the old version) Class object with same qualified name
> as the actually requested class.
> 
> It is somewhat worse than using weak references, as Introspector will
> release the old classes only when it first encounters any of the new classes
> and not immediately after Tomcat threw away the class loader (here
> "immediately" naturally means "as soon as GC notices it"), however it has
> the advantage of having no negative memory or performance impact on behalf
> of Introspector.
> 
> I guess that this "next time reloaded class is accessed from Velocity
> template" is an acceptable upper time limit for releasing old classes. If
> it's not good enough for your needs, you can always stimulate the
> Introspector to notice class reloads by processing a template that accesses
> your reloadable classes when the reload occurs. That is, if you have means
> for executing code on class reloads.

Not 100% sure on that one. It seems that at least Tomcat 3.3 drops the
whole app when there is a new class. I just tested a few times and
Tomcat reports removal and addition of context. The init methods of my
beans get called every time I distribute and new class files (the init
methods are called only when there are no stored beans in
ServletContext/HttpSession). So, I guess Tomcat is taking care of all
that, I hope at least...

Velocity, however, doesn't report a reload (I'm using non-singleton
model), although I have this in the servlet init():

----------------------------------------
/* Initialise Velocity */
  ve=new VelocityEngine();
  ve.init(p);
----------------------------------------

and Tomcat reports that the init of the servlet was executed. A bit
confusing...

Bojan

Re: performance questions

Posted by Attila Szegedi <sz...@freemail.hu>.
Geir and I are now on a different track: essentially we'll assume in
Introspector code that class reloading happened if introspection is
requested for a class, and the Introspector detects it already has a
*different* (probably the old version) Class object with same qualified name
as the actually requested class.

It is somewhat worse than using weak references, as Introspector will
release the old classes only when it first encounters any of the new classes
and not immediately after Tomcat threw away the class loader (here
"immediately" naturally means "as soon as GC notices it"), however it has
the advantage of having no negative memory or performance impact on behalf
of Introspector.

I guess that this "next time reloaded class is accessed from Velocity
template" is an acceptable upper time limit for releasing old classes. If
it's not good enough for your needs, you can always stimulate the
Introspector to notice class reloads by processing a template that accesses
your reloadable classes when the reload occurs. That is, if you have means
for executing code on class reloads.

Attila.


----- Original Message -----
From: "Bojan Smojver" <bo...@binarix.com>
To: <ve...@jakarta.apache.org>
Sent: Sunday, September 09, 2001 4:52 AM
Subject: Re: performance questions


> Bojan Smojver wrote:
> >
> > Attila Szegedi wrote:
> > >
> > > ----- Original Message -----
> > > From: "Geir Magnusson Jr." <ge...@optonline.net>
> > > To: <ve...@jakarta.apache.org>
> > > Sent: 2001. szeptember 7. 0:03
> > > Subject: Re: performance questions
> > >
> > > >
> > > > I am not sure what happens with Tomcat's classloader when you load a
new
> > > > jar.  I would think that if it's just your servlet, then the
Velocity
> > > stuff
> > > > wouldn't need to change.  The template cache will hold what it has.
The
> > > > introspector might accumulate gunk over time, but I wouldn't think
that
> > > > would be significant amounts of memory.  I assume that the JAR only
> > > contains
> > > > code?
> > > >
> > >
> > > Introspector holds a strong reference to Class objects, so it prevents
them
> > > from being unloaded. This way, not only does it accumulate method
cache
> > > information, but it also keeps those classes around together with
their code
> > > and every object reachable from their static fields. And that can
impose a
> > > significant memory leak in an environment where classes are reloaded
> > > frequently.
> > >
> > > This could be fixed with employment of weak references and removal of
> > > superfluous strong references:
> > > - using WeakHashMap instead of Hashtable for
Introspector.classMethodMaps
> > > - removing the clazz field from ClassMap (it could be passed on as a
> > > parameter from constructor to populateMethodCache(), and no other
method
> > > references it). This is worth doing regardless of other suggestions.
> > > - using WeakReference containing Method as values in
ClassMap.methodCache
> > > - using WeakReference containing Method as elements of list stored in
> > > MethodMap.methodByNameMap
> > >
> > > If people are comfortable with these changes, I can do them.
> > > Attila.
> >
> > This is really great stuff! I think I'm seeing memory leaks in my
> > servlet for exactly the same reason (I'm also loading classes, doing
> > introspection etc.).
> >
> > Thanks heaps!
> >
> > Bojan
>
> If you remember, a few weeks ago I posted a message about switching to
> 1.2-dev and noticing significant memory savings, around 30%. Geir
> pointed out that it probably wouldn't be that much...
>
> When I review that in the light of the above discussion of the
> Introspector issues, I think the increased memory usage had to do with
> the fact that, every once in a while, I would deploy new beans into my
> applications. Since my servlet detects that, loads the new classes and
> creates new instance of objects (beans), it seems that the old
> classes/methods would still be referenced in the Introspector and
> ClassMap of Velocity, so they'd just 'hang around' indefinitely, thus
> increasing memory usage.
>
> So, the deployment of 1.2-dev probably had very little to do with memory
> usage apart from the fact that the whole JVM was restarted and therefore
> references to all those old beans were gone as well. In other words
> memory usage probably dropped because all those caches were cleaned out.
>
> I've checked my servlet and where it's referencing the beans, classes
> and methods I'm loading and here are the findings:
>
> - class objects are referenced only from local variables, so when the
> method is finished executing, those class objects are ready for garbage
> collection
> - beans/methods are referenced as Hashtable values; the Hashtables are
> stored into ServletContext or HttpSession as attributes - so unless
> Tomcat has some major bugs in that area, when a session is gone, so
> should be the attribute and the Hashtable values with it; as for
> ServletContext, the attributes holding Hashtables are removed with every
> reload of the application and the actual bean objects are keyed by
> names, so new bean is always replacing an existing value - it is never
> added
> - the other source of memory leaks could be Tomcat's classloader - if
> it's hanging to previously loaded class objects - I don't know all that
> much about the mechanisms in Tomcat to comment
>
> That's what leads me to believe that memory savings I saw were result of
> the initial condition where memory leaks didn't yet occur, rather then
> actual memory savings.
>
> So, unless there are some horrible performance penalties in using Weak*
> thingies, I'm all for it. Actually, I'd be more then happy to give
> feedback once the patch becomes available.
>
> Bojan
>


Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
"Geir Magnusson Jr." wrote:
> 
> On 9/8/01 4:52 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> >
> > If you remember, a few weeks ago I posted a message about switching to
> > 1.2-dev and noticing significant memory savings, around 30%. Geir
> > pointed out that it probably wouldn't be that much...
> >
> > When I review that in the light of the above discussion of the
> > Introspector issues, I think the increased memory usage had to do with
> > the fact that, every once in a while, I would deploy new beans into my
> > applications. Since my servlet detects that, loads the new classes and
> > creates new instance of objects (beans), it seems that the old
> > classes/methods would still be referenced in the Introspector and
> > ClassMap of Velocity, so they'd just 'hang around' indefinitely, thus
> > increasing memory usage.
> >
> > So, the deployment of 1.2-dev probably had very little to do with memory
> > usage apart from the fact that the whole JVM was restarted and therefore
> > references to all those old beans were gone as well. In other words
> > memory usage probably dropped because all those caches were cleaned out.
> 
> Sure - what are you seeing now that a few weeks have gone by?

It is a bit over the initial size, by about 3 MB. Only 1 out of 10
applications received new beans... But, by all means, I don't want to
jump any conclusions.

> >
> > I've checked my servlet and where it's referencing the beans, classes
> > and methods I'm loading and here are the findings:
> >
> > - class objects are referenced only from local variables, so when the
> > method is finished executing, those class objects are ready for garbage
> > collection
> > - beans/methods are referenced as Hashtable values; the Hashtables are
> > stored into ServletContext or HttpSession as attributes - so unless
> > Tomcat has some major bugs in that area, when a session is gone, so
> > should be the attribute and the Hashtable values with it; as for
> > ServletContext, the attributes holding Hashtables are removed with every
> > reload of the application and the actual bean objects are keyed by
> > names, so new bean is always replacing an existing value - it is never
> > added
> > - the other source of memory leaks could be Tomcat's classloader - if
> > it's hanging to previously loaded class objects - I don't know all that
> > much about the mechanisms in Tomcat to comment
> >
> > That's what leads me to believe that memory savings I saw were result of
> > the initial condition where memory leaks didn't yet occur, rather then
> > actual memory savings.
> >
> > So, unless there are some horrible performance penalties in using Weak*
> > thingies, I'm all for it. Actually, I'd be more then happy to give
> > feedback once the patch becomes available.
> 
> I have been playing with Attila's idea of switching to strings vs. Classes
> for the introspector map, and I think all will be well.
> 
> What I think should happen is that we don't get fancy, but just dump the
> introspector cache once we notice something is amiss - that way we aren't
> trying to guess what the classloader is doing now, or in the future.  It's
> unsettling to assume what might be going on...
> 
> Since this is something that will happen infrequently, relatively speaking,
> then the penalty of refreshing the introspection information is small (and
> the piece of mind is large :)

This approach works well for me. I don't care if there is something old
in the cache, as long as the copies aren't accumulating. Once someone
hits the app that uses those old things, they get reloaded, so that's
perfectly cool. That's what my servlet does as well, it holds beans as
values in a Hashtable with bean names as keys.

> While playing with it, I remembered one small 'separate instance' fix I need
> to do before 1.2.  After that (and I want to run it by Attila to make sure
> it is what he was thinking ) then I have what I think is a simple
> implementation of his clever idea...  There is no complexity cost or
> algorithm change, so I think it will be safe to put in 1.2.

This sounds even better. It would be nice to have it in 1.2.

Bojan

Multiple-ClassLoader safe Introspector

Posted by Paulo Gaspar <pa...@krankikom.de>.
There is a simple way of having a Multiple-ClassLoader safe Introspector:
  LRU cache.

There are a couple of LRU Maps/caches in Jakarta. The simplest one I am 
aware of is the LRUMap at the commons-collections project (I have a 
lighter/faster version of this one in tests.)

If one finds an appropriate strategy to evict unused introspection data
from the cache, everything will end up being GCed "sometime" (albeit 
possibly quite a bit after the respective CL is invalidated).

Possible strategies to trigger eviction:
 - When free memory gets lower than X (that is how Cocoon 2's 
   MRUMemoryStore triggers eviction of cached objects);
 - Time interval.


Possible strategies to find out how many objects to evict:
 - Until free memory goes back to acceptable levels (again, as in 
   Cocoon 2's MRUMemoryStore);
 - Introspected data not used for more than Y minutes.


It would also be nice to have an API call just to evict all cached 
introspection data for a given ClassLoader.


Disadvantages: 
  * Added configuration complexity of the Introspection Cache;
  * Maybe it would be slightly slower (just the time of moving updating
    the LRU list for each use).
    

Advantages:
  * It is possible to use a single cache for multiple class loaders and
    even for multiple "legal" versions of the same class.

I do not talk about complexity because a simplistic Cache based on a 
LRUMap with a time based eviction strategy would be even simpler than 
the new cache.


Again, it would be nice to change Introspection Cache implementations 
at will. Maybe an idea for version 2... or 3...


Have fun,
Paulo Gaspar


RE: performance questions - faster Introspector

Posted by Paulo Gaspar <pa...@krankikom.de>.
Thanks!
But it just an easy bit after you did all the really hard work.
=:o)

Have fun,
Paulo

> -----Original Message-----
> From: Attila Szegedi [mailto:szegedia@freemail.hu]
> Sent: Monday, September 10, 2001 10:36 AM
> 
> Nice idea. Realy good.
> Attila.
> 
> ----- Original Message ----- 
> From: "Paulo Gaspar" <pa...@krankikom.de>
> To: <ve...@jakarta.apache.org>
> Sent: 2001. szeptember 10. 6:09
> Subject: RE: performance questions - faster Introspector
> 
> 
> > Attached is a little modification to Attila's great work on the
> > Introspector.
> > 
> > I just gave it a little twist by keeping everything keyed by Class
> > instead of by class name. To do it was necessary to add an extra
> > map, but this one only gets to be used when there is a new class or
> > when a Class Loader got dumped.
> > 
> > This should keep things FASTER, especially after the introspection
> > cache is filled.
> > 
> > I am attaching the whole file, but there are not that many changes
> > from Attila's version. Please make a diff to see them.
> > 
> > 
> > Have fun,
> > Paulo Gaspar
> > 
> 
> 

Re: performance questions - faster Introspector

Posted by Attila Szegedi <sz...@freemail.hu>.
Nice idea. Realy good.
Attila.

----- Original Message ----- 
From: "Paulo Gaspar" <pa...@krankikom.de>
To: <ve...@jakarta.apache.org>
Sent: 2001. szeptember 10. 6:09
Subject: RE: performance questions - faster Introspector


> Attached is a little modification to Attila's great work on the
> Introspector.
> 
> I just gave it a little twist by keeping everything keyed by Class
> instead of by class name. To do it was necessary to add an extra
> map, but this one only gets to be used when there is a new class or
> when a Class Loader got dumped.
> 
> This should keep things FASTER, especially after the introspection
> cache is filled.
> 
> I am attaching the whole file, but there are not that many changes
> from Attila's version. Please make a diff to see them.
> 
> 
> Have fun,
> Paulo Gaspar
> 



Re: performance questions - faster Introspector

Posted by Bojan Smojver <bo...@binarix.com>.
Attila Szegedi wrote:
> 
> ----- Original Message -----
> From: "Bojan Smojver" <bo...@binarix.com>
> To: <ve...@jakarta.apache.org>
> Sent: 2001. szeptember 10. 10:01
> Subject: Re: performance questions - faster Introspector
> 
> >
> > One other idea might be to not have static fields in the Introspector,
> > but rather make them regular private class fields and then keep the
> > logic simple since it would already be per classloader. But that would
> > probably increase the overall memory usage of the cache since there
> > could be duplicates of classes/methods in multiple instances of
> > Introspector cache. I'm not really sure what I'm talking about here but
> > what the heck...
> >
> 
> Umm. From this point of view, it really makes no difference if the cache is
> accessed through a static field, or through instance field of a singleton
> (which is itself probably also referred by a static field). What REALLY
> helps here is to have Velocity classes loaded through the same disposable
> class loader used to load your classes - that is, have them in WEB-INF/lib
> or WEB-INF/classes.
> 
> Attila.

Just thinking out loud...

My understanding is that RuntimeInstance creates an Introspector object
and VelocityEngine creates a RuntimeInstance. So, there is a 1 to 1
relationship between a VelocityEngine instance and an Introspector
instance.

Currently, if Velocity jar is in Tomcat's lib/apps, that would mean that
cache is one for all apps since the classloader for lib/apps keeps one
copy of static fields for all Introspector objects. If Velocity jar was
in WEB-INF/lib then each Introspector object would share the same static
fields within that app.

If fields that are holding the maps in the Introspector were not static,
that would mean that there would be one copy of them in each
Introspector, ie. one per VelocityEngine. I'm not sure if that's good,
bad or ugly, but you're correct, it wouldn't be per classloader, it
would be per instance of VelocityEngine, so it would be even more
granular then classloader. Aieee!

OK, I'm going to take a nap now, my head hurts...

Bojan

Re: performance questions - faster Introspector

Posted by Attila Szegedi <sz...@freemail.hu>.
----- Original Message -----
From: "Bojan Smojver" <bo...@binarix.com>
To: <ve...@jakarta.apache.org>
Sent: 2001. szeptember 10. 10:01
Subject: Re: performance questions - faster Introspector


>
> One other idea might be to not have static fields in the Introspector,
> but rather make them regular private class fields and then keep the
> logic simple since it would already be per classloader. But that would
> probably increase the overall memory usage of the cache since there
> could be duplicates of classes/methods in multiple instances of
> Introspector cache. I'm not really sure what I'm talking about here but
> what the heck...
>

Umm. From this point of view, it really makes no difference if the cache is
accessed through a static field, or through instance field of a singleton
(which is itself probably also referred by a static field). What REALLY
helps here is to have Velocity classes loaded through the same disposable
class loader used to load your classes - that is, have them in WEB-INF/lib
or WEB-INF/classes.

Attila.



Re: performance questions - faster Introspector

Posted by Jon Stevens <jo...@latchkey.com>.
on 9/10/01 1:01 AM, "Bojan Smojver" <bo...@binarix.com> wrote:

> One other idea might be to not have static fields in the Introspector,
> but rather make them regular private class fields and then keep the
> logic simple since it would already be per classloader. But that would
> probably increase the overall memory usage of the cache since there
> could be duplicates of classes/methods in multiple instances of
> Introspector cache. I'm not really sure what I'm talking about here but
> what the heck...

+1

That sounds like the best and easiest solution to me.

-jon


Re: performance questions - faster Introspector

Posted by Bojan Smojver <bo...@binarix.com>.
Attila Szegedi wrote:
> 
> Hmm. So, if I'm right you'd be happier with per-classloader dumping of
> cache? (I have this already coded, but have phased it out in agreement with
> Geir in spirit of the KISS principle).
> 
> Attila.

Honestly, I'm just a happy Velocity user. Even if I had to stop/start
Tomcat every week to prevent memory leaks it'd be fine by me. Well,
almost, anyway.

However, this is like with one of those Linux kernel locking issues - do
we make things more granular and more complex or less granular and less
complex (not that I'd be able to program any)? I guess it depends on
what you want to achieve - on a single CPU system the first approach is
an overkill, on a 64 CPU machine it's a necessity. You know, the Irix
syndrome.

To get back to Velocity, since non-singleton model was introduced, I
guess it makes sense to have Velocity jar in lib/apps. And on a big
server running a lot of Velocity apps, especially if some of them are
experimental (ie. you let people poke around, deploy their own
templates, beans etc.), dumping of the whole lot would hurt other apps
(potentially other customers). So, yes I'd be inclined to vote for
complexity here.

One other idea might be to not have static fields in the Introspector,
but rather make them regular private class fields and then keep the
logic simple since it would already be per classloader. But that would
probably increase the overall memory usage of the cache since there
could be duplicates of classes/methods in multiple instances of
Introspector cache. I'm not really sure what I'm talking about here but
what the heck...

Either way, I'm OK. Slightly more OK with a complex solution though (I
actually rather liked the Weak* thingies but someone pointed out the
performance penalty).

Bojan

Re: performance questions - faster Introspector

Posted by Bojan Smojver <bo...@binarix.com>.
Attila Szegedi wrote:

> Incorporate copy tasks in your Ant script that will dispatch the latest
> velocity.jar everywhere from a central position. Ant is ideal for lazy
> people. After all, we're using it since we're lazy to manually invoke the
> compiler, jar classes, copy them, test them, generate javadocs etc. every
> time.

I used to have a symlink in WEB-INF/lib to a central Velocity jar (when
I used signleton model) and then I'd do something like:

----------------------------
for i in customer1 customer2 ...;
  do cd $i; ant test-deploy prod-deploy; cd ..;
done
----------------------------

and all sites would be updated. I might go back to that...

Bojan

Re: performance questions - faster Introspector

Posted by Attila Szegedi <sz...@freemail.hu>.
----- Original Message -----
From: "Bojan Smojver" <bo...@binarix.com>
To: <ve...@jakarta.apache.org>
Sent: 2001. szeptember 10. 11:30
Subject: Re: performance questions - faster Introspector


>
> You know what they say - people do things because they're lazy. So do I.
> With number of virtual hosts/apps growing, I have to make sure everyone
> gets the updated Velocity jar. And being a lazy bastard I am... One
> solution is to symlink the thing, works well. Ant (my site build tool)
> doesn't like those much though when it copies files around, so I had to
> use platform specific hacks and that's ugly. I used to have multiple
> copies of Velocity around before, I just wanted to clean up the mess.

Incorporate copy tasks in your Ant script that will dispatch the latest
velocity.jar everywhere from a central position. Ant is ideal for lazy
people. After all, we're using it since we're lazy to manually invoke the
compiler, jar classes, copy them, test them, generate javadocs etc. every
time.

Attila.



Re: performance questions - faster Introspector

Posted by Bojan Smojver <bo...@binarix.com>.
"Geir Magnusson Jr." wrote:
> 
> On 9/9/01 11:30 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> 
> > "Geir Magnusson Jr." wrote:
> >>
> >> Two points on this :
> >>
> >> 1) If you have a big installation, and you share one instance of Velocity
> >> across all of your webapps via Tomcat's lib, you are asking for trouble, I
> >> think.  I can't see much benefit to that other than desire to avoid multiple
> >> copies of the jar.  If that is the case, and you want to keep your webapps
> >> partitioned, then use the separate instance runtime (which I think you are
> >> doing, Bojan).  If *that* is the case, then I think you are safe, as nothing
> >> is a singleton in the separate instance, your servlet holds the reference to
> >> it, and when your servlet is recycled on the classloader change, then you
> >> let go of the refrerence to the vel runtime, and get a new one.  All is
> >> well.
> >
> > You know what they say - people do things because they're lazy. So do I.
> > With number of virtual hosts/apps growing, I have to make sure everyone
> > gets the updated Velocity jar. And being a lazy bastard I am... One
> > solution is to symlink the thing, works well. Ant (my site build tool)
> > doesn't like those much though when it copies files around, so I had to
> > use platform specific hacks and that's ugly. I used to have multiple
> > copies of Velocity around before, I just wanted to clean up the mess.
> 
> I think you misunderstood me

Could be. Sorry about that.

> - I think that it is a valid reason to have one
> on top to avoid duplication. (You may have troubles when one app wants a new
> version, but I guess you can drop into the webapp itself then.)

> I tend to keep them separate, as I don't have a large number, and I want the
> ability for each webapp to have different versions.

Since I really started using Velocity from version 1.0, not much has
changed (which can only be good) in the way templates work. I only have
one servlet, so when I move forward, I move forward in all apps (except
for the legacy JSP stuff).

> But since you are using separate runtimes for each servlet... (read below..)
>
> > Not to worry, I can go either way, I just wanted to use Velocity as one
> > of the 'standard' Tomcat app libraries, without the need to do anything
> > special within each app.
> 
> Since you are using the separate runtime instance model in your servlet
> (VelocityEngine), then I think there is no problem if you keep it in
> tomcat/lib because each servlet has it's own instance of the engine.

Cool :-)

> Before the fixes I committed earlier today, even the separate instance
> runtime would have problems with the introspector collecting junk, as the
> Introspector was left as a singleton (my fault... It's fixed now).
> 
> Now, by using the separate instance in your servlet, when your CL gets
> dumped, the servlet gets dumped, so the VelocityEngine will eventually get
> GC'd, and since the Introspector is no longer a Singleton, it will get GC'd
> as well.
> 
> Unless I am missing something (quite possibly, as I am on vacation and
> rather muddy headed...), all should be well for you.
> 
> We still should add the change, I think. (I am merging the current state,
> Attila's patch, and Paulo's improvement...)

I've seen the comitted patch and it uses private class variables, so I
guess it will there will be 1 to 1 relationship between VelocityEngine,
RuntimeInstance and Introspector, which means there will ba quite a few
Introspectors around once all those VelocityEngines kick in. I'll
download and give it a try.

Bojan

Re: performance questions - faster Introspector (committed...)

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
Ok - I put together the minimalist version of Attila's reengineering and the
clever patch from Paulo into one version that is up to date with CVS head.

I believe I have it right, although some will attest that I have been a
dunderhead of late, so I might have screwed this up too.  I love this
vacation, but I am now ready to get back to things (which explains why I am
up late doing this...)

Anyhow, I really like this - it's very simple, very clean, keeps Class as
the key, and the cache dumping is simple.

While this is 'provisional' because of 1.2 coming up, the whole thing is
simple enough that I believe that it poses little risk, and would think that
if all is well, we can beat on it a few days and then let it roll into 1.2.
It's simple to back out of because the changes are so localized, so there is
little risk to 1.2 if something is wrong.
 
geir

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


RE: performance questions - faster Introspector

Posted by Paulo Gaspar <pa...@krankikom.de>.
> Since you are using the separate runtime instance model in your servlet
> (VelocityEngine), then I think there is no problem if you keep it in
> tomcat/lib because each servlet has it's own instance of the engine.

Now, the tricky bit is that the singleton components are still available.
If someone (more than one) uses it, it will be a mess again.

But it will be a mess on many other levels besides the introspector.


Have fun,
Paulo Gaspar



> -----Original Message-----
> From: Geir Magnusson Jr. [mailto:geirm@optonline.net]
> Sent: Monday, September 10, 2001 11:42 AM
>
>
> On 9/9/01 11:30 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
>
> > "Geir Magnusson Jr." wrote:
> >>
> >> Two points on this :
> >>
> >> 1) If you have a big installation, and you share one instance
> of Velocity
> >> across all of your webapps via Tomcat's lib, you are asking
> for trouble, I
> >> think.  I can't see much benefit to that other than desire to
> avoid multiple
> >> copies of the jar.  If that is the case, and you want to keep
> your webapps
> >> partitioned, then use the separate instance runtime (which I
> think you are
> >> doing, Bojan).  If *that* is the case, then I think you are
> safe, as nothing
> >> is a singleton in the separate instance, your servlet holds
> the reference to
> >> it, and when your servlet is recycled on the classloader
> change, then you
> >> let go of the refrerence to the vel runtime, and get a new one.  All is
> >> well.
> >
> > You know what they say - people do things because they're lazy. So do I.
> > With number of virtual hosts/apps growing, I have to make sure everyone
> > gets the updated Velocity jar. And being a lazy bastard I am... One
> > solution is to symlink the thing, works well. Ant (my site build tool)
> > doesn't like those much though when it copies files around, so I had to
> > use platform specific hacks and that's ugly. I used to have multiple
> > copies of Velocity around before, I just wanted to clean up the mess.
>
> I think you misunderstood me - I think that it is a valid reason
> to have one
> on top to avoid duplication. (You may have troubles when one app
> wants a new
> version, but I guess you can drop into the webapp itself then.)
>
> I tend to keep them separate, as I don't have a large number, and
> I want the
> ability for each webapp to have different versions.
>
> But since you are using separate runtimes for each servlet...
> (read below..)
>
> > Not to worry, I can go either way, I just wanted to use Velocity as one
> > of the 'standard' Tomcat app libraries, without the need to do anything
> > special within each app.
>
> Since you are using the separate runtime instance model in your servlet
> (VelocityEngine), then I think there is no problem if you keep it in
> tomcat/lib because each servlet has it's own instance of the engine.
>
> Before the fixes I committed earlier today, even the separate instance
> runtime would have problems with the introspector collecting junk, as the
> Introspector was left as a singleton (my fault... It's fixed now).
>
> Now, by using the separate instance in your servlet, when your CL gets
> dumped, the servlet gets dumped, so the VelocityEngine will eventually get
> GC'd, and since the Introspector is no longer a Singleton, it
> will get GC'd
> as well.
>
> Unless I am missing something (quite possibly, as I am on vacation and
> rather muddy headed...), all should be well for you.
>
> We still should add the change, I think. (I am merging the current state,
> Attila's patch, and Paulo's improvement...)
>
> geir
>
>
> >> 2) I still think we are adding unnecessary complexityh re the
> >> per-classloader dumping.  KISS.
> >
> > No worries.
> >
> > Bojan
>
> --
> Geir Magnusson Jr.     geirm@optonline.net
> System and Software Consulting
> Developing for the web?  See http://jakarta.apache.org/velocity/
> If you look up, there are no limits - Japanese Proverb
>


Re: performance questions - faster Introspector

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/9/01 11:30 PM, "Bojan Smojver" <bo...@binarix.com> wrote:

> "Geir Magnusson Jr." wrote:
>> 
>> Two points on this :
>> 
>> 1) If you have a big installation, and you share one instance of Velocity
>> across all of your webapps via Tomcat's lib, you are asking for trouble, I
>> think.  I can't see much benefit to that other than desire to avoid multiple
>> copies of the jar.  If that is the case, and you want to keep your webapps
>> partitioned, then use the separate instance runtime (which I think you are
>> doing, Bojan).  If *that* is the case, then I think you are safe, as nothing
>> is a singleton in the separate instance, your servlet holds the reference to
>> it, and when your servlet is recycled on the classloader change, then you
>> let go of the refrerence to the vel runtime, and get a new one.  All is
>> well.
> 
> You know what they say - people do things because they're lazy. So do I.
> With number of virtual hosts/apps growing, I have to make sure everyone
> gets the updated Velocity jar. And being a lazy bastard I am... One
> solution is to symlink the thing, works well. Ant (my site build tool)
> doesn't like those much though when it copies files around, so I had to
> use platform specific hacks and that's ugly. I used to have multiple
> copies of Velocity around before, I just wanted to clean up the mess.

I think you misunderstood me - I think that it is a valid reason to have one
on top to avoid duplication. (You may have troubles when one app wants a new
version, but I guess you can drop into the webapp itself then.)

I tend to keep them separate, as I don't have a large number, and I want the
ability for each webapp to have different versions.

But since you are using separate runtimes for each servlet... (read below..)

> Not to worry, I can go either way, I just wanted to use Velocity as one
> of the 'standard' Tomcat app libraries, without the need to do anything
> special within each app.

Since you are using the separate runtime instance model in your servlet
(VelocityEngine), then I think there is no problem if you keep it in
tomcat/lib because each servlet has it's own instance of the engine.

Before the fixes I committed earlier today, even the separate instance
runtime would have problems with the introspector collecting junk, as the
Introspector was left as a singleton (my fault... It's fixed now).

Now, by using the separate instance in your servlet, when your CL gets
dumped, the servlet gets dumped, so the VelocityEngine will eventually get
GC'd, and since the Introspector is no longer a Singleton, it will get GC'd
as well.  

Unless I am missing something (quite possibly, as I am on vacation and
rather muddy headed...), all should be well for you.

We still should add the change, I think. (I am merging the current state,
Attila's patch, and Paulo's improvement...)

geir


>> 2) I still think we are adding unnecessary complexityh re the
>> per-classloader dumping.  KISS.
> 
> No worries.
> 
> Bojan

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions - faster Introspector

Posted by Bojan Smojver <bo...@binarix.com>.
"Geir Magnusson Jr." wrote:
> 
> Two points on this :
> 
> 1) If you have a big installation, and you share one instance of Velocity
> across all of your webapps via Tomcat's lib, you are asking for trouble, I
> think.  I can't see much benefit to that other than desire to avoid multiple
> copies of the jar.  If that is the case, and you want to keep your webapps
> partitioned, then use the separate instance runtime (which I think you are
> doing, Bojan).  If *that* is the case, then I think you are safe, as nothing
> is a singleton in the separate instance, your servlet holds the reference to
> it, and when your servlet is recycled on the classloader change, then you
> let go of the refrerence to the vel runtime, and get a new one.  All is
> well.

You know what they say - people do things because they're lazy. So do I.
With number of virtual hosts/apps growing, I have to make sure everyone
gets the updated Velocity jar. And being a lazy bastard I am... One
solution is to symlink the thing, works well. Ant (my site build tool)
doesn't like those much though when it copies files around, so I had to
use platform specific hacks and that's ugly. I used to have multiple
copies of Velocity around before, I just wanted to clean up the mess.
Not to worry, I can go either way, I just wanted to use Velocity as one
of the 'standard' Tomcat app libraries, without the need to do anything
special within each app.

> 2) I still think we are adding unnecessary complexityh re the
> per-classloader dumping.  KISS.

No worries.

Bojan

Re: performance questions - faster Introspector

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
Two points on this :

1) If you have a big installation, and you share one instance of Velocity
across all of your webapps via Tomcat's lib, you are asking for trouble, I
think.  I can't see much benefit to that other than desire to avoid multiple
copies of the jar.  If that is the case, and you want to keep your webapps
partitioned, then use the separate instance runtime (which I think you are
doing, Bojan).  If *that* is the case, then I think you are safe, as nothing
is a singleton in the separate instance, your servlet holds the reference to
it, and when your servlet is recycled on the classloader change, then you
let go of the refrerence to the vel runtime, and get a new one.  All is
well.

2) I still think we are adding unnecessary complexityh re the
per-classloader dumping.  KISS.

geir



On 9/9/01 9:29 PM, "Attila Szegedi" <sz...@freemail.hu> wrote:

> Hmm. So, if I'm right you'd be happier with per-classloader dumping of
> cache? (I have this already coded, but have phased it out in agreement with
> Geir in spirit of the KISS principle).
> 
> Attila.
> 
> ----- Original Message -----
> From: "Bojan Smojver" <bo...@binarix.com>
> To: <ve...@jakarta.apache.org>
> Sent: 2001. szeptember 10. 8:32
> Subject: Re: performance questions - faster Introspector
> 
> 
>> "Geir Magnusson Jr." wrote:
>>> 
>>> On 9/9/01 6:09 PM, "Paulo Gaspar" <pa...@krankikom.de> wrote:
>>> 
>>>> Attached is a little modification to Attila's great work on the
>>>> Introspector.
>>>> 
>>>> I just gave it a little twist by keeping everything keyed by Class
>>>> instead of by class name. To do it was necessary to add an extra
>>>> map, but this one only gets to be used when there is a new class or
>>>> when a Class Loader got dumped.
>>> 
>>> Note, for simplicity, we are going to knock out the 'by classloader'
> stuff
>>> and just dump the whole pile.
>> 
>> If Tomcat lib/apps installation of Velocity is used, then the
>> Introspector cache for all apps would be cleaned out since there would
>> be only one of those caches hanging around. In other words, if there are
>> many applications within one Tomcat, one has to be careful about
>> deployment of new classes as that might cause jerks on heavily loaded
>> servers.
>> 
>> Hmm, OK, promise to deploy only during the graveyard shift :-)
>> 
>> Bojan
>> 
> 

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions - faster Introspector

Posted by Attila Szegedi <sz...@freemail.hu>.
Hmm. So, if I'm right you'd be happier with per-classloader dumping of
cache? (I have this already coded, but have phased it out in agreement with
Geir in spirit of the KISS principle).

Attila.

----- Original Message -----
From: "Bojan Smojver" <bo...@binarix.com>
To: <ve...@jakarta.apache.org>
Sent: 2001. szeptember 10. 8:32
Subject: Re: performance questions - faster Introspector


> "Geir Magnusson Jr." wrote:
> >
> > On 9/9/01 6:09 PM, "Paulo Gaspar" <pa...@krankikom.de> wrote:
> >
> > > Attached is a little modification to Attila's great work on the
> > > Introspector.
> > >
> > > I just gave it a little twist by keeping everything keyed by Class
> > > instead of by class name. To do it was necessary to add an extra
> > > map, but this one only gets to be used when there is a new class or
> > > when a Class Loader got dumped.
> >
> > Note, for simplicity, we are going to knock out the 'by classloader'
stuff
> > and just dump the whole pile.
>
> If Tomcat lib/apps installation of Velocity is used, then the
> Introspector cache for all apps would be cleaned out since there would
> be only one of those caches hanging around. In other words, if there are
> many applications within one Tomcat, one has to be careful about
> deployment of new classes as that might cause jerks on heavily loaded
> servers.
>
> Hmm, OK, promise to deploy only during the graveyard shift :-)
>
> Bojan
>


Re: performance questions - faster Introspector

Posted by Bojan Smojver <bo...@binarix.com>.
"Geir Magnusson Jr." wrote:
> 
> On 9/9/01 6:09 PM, "Paulo Gaspar" <pa...@krankikom.de> wrote:
> 
> > Attached is a little modification to Attila's great work on the
> > Introspector.
> >
> > I just gave it a little twist by keeping everything keyed by Class
> > instead of by class name. To do it was necessary to add an extra
> > map, but this one only gets to be used when there is a new class or
> > when a Class Loader got dumped.
> 
> Note, for simplicity, we are going to knock out the 'by classloader' stuff
> and just dump the whole pile.

If Tomcat lib/apps installation of Velocity is used, then the
Introspector cache for all apps would be cleaned out since there would
be only one of those caches hanging around. In other words, if there are
many applications within one Tomcat, one has to be careful about
deployment of new classes as that might cause jerks on heavily loaded
servers.

Hmm, OK, promise to deploy only during the graveyard shift :-)

Bojan

Re: performance questions - faster Introspector

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/9/01 6:09 PM, "Paulo Gaspar" <pa...@krankikom.de> wrote:

> Attached is a little modification to Attila's great work on the
> Introspector.
> 
> I just gave it a little twist by keeping everything keyed by Class
> instead of by class name. To do it was necessary to add an extra
> map, but this one only gets to be used when there is a new class or
> when a Class Loader got dumped.

Note, for simplicity, we are going to knock out the 'by classloader' stuff
and just dump the whole pile.
 
> This should keep things FASTER, especially after the introspection
> cache is filled.

I think of a classloader getting dumped as a momentous occurrence, so
keeping the code simple and free of assumptions at the cost of a little
one-time overhead is a fair trade, I think.
 
> I am attaching the whole file, but there are not that many changes
> from Attila's version. Please make a diff to see them.
> 

I will take a look and integrate all later tonight.

geir


-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


RE: performance questions - faster Introspector

Posted by Paulo Gaspar <pa...@krankikom.de>.
Attached is a little modification to Attila's great work on the
Introspector.

I just gave it a little twist by keeping everything keyed by Class
instead of by class name. To do it was necessary to add an extra
map, but this one only gets to be used when there is a new class or
when a Class Loader got dumped.

This should keep things FASTER, especially after the introspection
cache is filled.

I am attaching the whole file, but there are not that many changes
from Attila's version. Please make a diff to see them.


Have fun,
Paulo Gaspar

> -----Original Message-----
> From: Geir Magnusson Jr. [mailto:geirm@optonline.net]
> Sent: Sunday, September 09, 2001 8:21 PM
> To: velocity-dev@jakarta.apache.org
> Subject: Re: performance questions
>
>
> On 9/9/01 3:24 AM, "Attila Szegedi" <sz...@freemail.hu> wrote:
>
> > (I've redirected this to velocity-dev, hope you don't mind)
> >
> > Here's my stab at having Introspector detect class reloads and
> discard no
> > longer relevant ClassMaps. Right now it might seem a bit compex, as it
> > discards ClassMaps at class loader granularity. However if it
> is not granted
> > the required "getClassLoader" RuntimePermission, then it falls back
> > gracefully and simply clears the whole cache when it detects
> what seems like
> > a class reload.
>
>
> This is great - this is the same strategy that I took (which was
> really what
> you described in the first place), but didn't separate by classloader.  I
> just dumped the entire pile when something changed.
>
> I made some small changes to introspector for the separate runtime that I
> will check in today, so I will dump my classloader-change changes
> and put in
> yours after that and provisionally checkin so people can see if it solves
> the problem (it should...)
>
> I am still wary about two things, the general performance and the
> complexity
> of dumping all in a classloader, as we are assuming a lot there.
> Of course,
> dumping all is pretty inefficient, so dumping by classloader is smarter.
> However... :)
>
> >
> > I'm including both the diffs and the complete modified files (as
> > Introspector underwent a major rewamp, I feel it's better comprehensible
> > from complete source than from the diff.)
> >
> > I've run it against the test suite and it fails on single test,
> but I assume
> > it has nothing to do with these changes:
> >
> >    [java] There was 1 failure:
> >    [java] 1)
> > EncodingTestCase(org.apache.velocity.test.EncodingTestCase)junit.
> > framework.AssertionFailedError: Output 2 incorrect.
> >    [java]     at
> > org.apache.velocity.test.EncodingTestCase.runTest(EncodingTes
> > tCase.java:170)
> >    [java]
> >    [java] FAILURES!!!
> >    [java] Tests run: 1,  Failures: 1,  Errors: 0
> >    [java]
>
> That's weird...  Did it work before the change?  I wonder if it's output
> line terminator related.  I will toss in a small fix to see if
> that changes
> it for you.
>
> > In meanwhile, I'm thinking of making a test case specifically for this
> > functionality.
>
> geir
>
> --
> Geir Magnusson Jr.     geirm@optonline.net
> System and Software Consulting
> Developing for the web?  See http://jakarta.apache.org/velocity/
> If you look up, there are no limits - Japanese Proverb
>

Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/9/01 3:24 AM, "Attila Szegedi" <sz...@freemail.hu> wrote:

> (I've redirected this to velocity-dev, hope you don't mind)
> 
> Here's my stab at having Introspector detect class reloads and discard no
> longer relevant ClassMaps. Right now it might seem a bit compex, as it
> discards ClassMaps at class loader granularity. However if it is not granted
> the required "getClassLoader" RuntimePermission, then it falls back
> gracefully and simply clears the whole cache when it detects what seems like
> a class reload.


This is great - this is the same strategy that I took (which was really what
you described in the first place), but didn't separate by classloader.  I
just dumped the entire pile when something changed.

I made some small changes to introspector for the separate runtime that I
will check in today, so I will dump my classloader-change changes and put in
yours after that and provisionally checkin so people can see if it solves
the problem (it should...)

I am still wary about two things, the general performance and the complexity
of dumping all in a classloader, as we are assuming a lot there.  Of course,
dumping all is pretty inefficient, so dumping by classloader is smarter.
However... :)

> 
> I'm including both the diffs and the complete modified files (as
> Introspector underwent a major rewamp, I feel it's better comprehensible
> from complete source than from the diff.)
> 
> I've run it against the test suite and it fails on single test, but I assume
> it has nothing to do with these changes:
> 
>    [java] There was 1 failure:
>    [java] 1)
> EncodingTestCase(org.apache.velocity.test.EncodingTestCase)junit.
> framework.AssertionFailedError: Output 2 incorrect.
>    [java]     at
> org.apache.velocity.test.EncodingTestCase.runTest(EncodingTes
> tCase.java:170)
>    [java]
>    [java] FAILURES!!!
>    [java] Tests run: 1,  Failures: 1,  Errors: 0
>    [java]

That's weird...  Did it work before the change?  I wonder if it's output
line terminator related.  I will toss in a small fix to see if that changes
it for you.
 
> In meanwhile, I'm thinking of making a test case specifically for this
> functionality.

geir

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Attila Szegedi <sz...@freemail.hu>.
(I've redirected this to velocity-dev, hope you don't mind)

Here's my stab at having Introspector detect class reloads and discard no
longer relevant ClassMaps. Right now it might seem a bit compex, as it
discards ClassMaps at class loader granularity. However if it is not granted
the required "getClassLoader" RuntimePermission, then it falls back
gracefully and simply clears the whole cache when it detects what seems like
a class reload.

I'm including both the diffs and the complete modified files (as
Introspector underwent a major rewamp, I feel it's better comprehensible
from complete source than from the diff.)

I've run it against the test suite and it fails on single test, but I assume
it has nothing to do with these changes:

     [java] There was 1 failure:
     [java] 1)
EncodingTestCase(org.apache.velocity.test.EncodingTestCase)junit.
framework.AssertionFailedError: Output 2 incorrect.
     [java]     at
org.apache.velocity.test.EncodingTestCase.runTest(EncodingTes
tCase.java:170)
     [java]
     [java] FAILURES!!!
     [java] Tests run: 1,  Failures: 1,  Errors: 0
     [java]

In meanwhile, I'm thinking of making a test case specifically for this
functionality.

Attila.


Re: performance questions

Posted by Attila Szegedi <sz...@freemail.hu>.
I'm also in process of implementing it... Maybe we should look at each
other's solution and merge the ideas.

Attila.

----- Original Message -----
From: "Geir Magnusson Jr." <ge...@optonline.net>
To: <ve...@jakarta.apache.org>
Sent: Sunday, September 09, 2001 9:28 AM
Subject: Re: performance questions


> On 9/8/01 4:52 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> >
> > If you remember, a few weeks ago I posted a message about switching to
> > 1.2-dev and noticing significant memory savings, around 30%. Geir
> > pointed out that it probably wouldn't be that much...
> >
> > When I review that in the light of the above discussion of the
> > Introspector issues, I think the increased memory usage had to do with
> > the fact that, every once in a while, I would deploy new beans into my
> > applications. Since my servlet detects that, loads the new classes and
> > creates new instance of objects (beans), it seems that the old
> > classes/methods would still be referenced in the Introspector and
> > ClassMap of Velocity, so they'd just 'hang around' indefinitely, thus
> > increasing memory usage.
> >
> > So, the deployment of 1.2-dev probably had very little to do with memory
> > usage apart from the fact that the whole JVM was restarted and therefore
> > references to all those old beans were gone as well. In other words
> > memory usage probably dropped because all those caches were cleaned out.
>
> Sure - what are you seeing now that a few weeks have gone by?
>
> >
> > I've checked my servlet and where it's referencing the beans, classes
> > and methods I'm loading and here are the findings:
> >
> > - class objects are referenced only from local variables, so when the
> > method is finished executing, those class objects are ready for garbage
> > collection
> > - beans/methods are referenced as Hashtable values; the Hashtables are
> > stored into ServletContext or HttpSession as attributes - so unless
> > Tomcat has some major bugs in that area, when a session is gone, so
> > should be the attribute and the Hashtable values with it; as for
> > ServletContext, the attributes holding Hashtables are removed with every
> > reload of the application and the actual bean objects are keyed by
> > names, so new bean is always replacing an existing value - it is never
> > added
> > - the other source of memory leaks could be Tomcat's classloader - if
> > it's hanging to previously loaded class objects - I don't know all that
> > much about the mechanisms in Tomcat to comment
> >
> > That's what leads me to believe that memory savings I saw were result of
> > the initial condition where memory leaks didn't yet occur, rather then
> > actual memory savings.
> >
> > So, unless there are some horrible performance penalties in using Weak*
> > thingies, I'm all for it. Actually, I'd be more then happy to give
> > feedback once the patch becomes available.
>
> I have been playing with Attila's idea of switching to strings vs. Classes
> for the introspector map, and I think all will be well.
>
> What I think should happen is that we don't get fancy, but just dump the
> introspector cache once we notice something is amiss - that way we aren't
> trying to guess what the classloader is doing now, or in the future.  It's
> unsettling to assume what might be going on...
>
> Since this is something that will happen infrequently, relatively
speaking,
> then the penalty of refreshing the introspection information is small (and
> the piece of mind is large :)
>
> While playing with it, I remembered one small 'separate instance' fix I
need
> to do before 1.2.  After that (and I want to run it by Attila to make sure
> it is what he was thinking ) then I have what I think is a simple
> implementation of his clever idea...  There is no complexity cost or
> algorithm change, so I think it will be safe to put in 1.2.
>
> geir
>
>
> --
> Geir Magnusson Jr.     geirm@optonline.net
> System and Software Consulting
> Developing for the web?  See http://jakarta.apache.org/velocity/
> If you look up, there are no limits - Japanese Proverb
>
>


Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/8/01 4:52 PM, "Bojan Smojver" <bo...@binarix.com> wrote:
> 
> If you remember, a few weeks ago I posted a message about switching to
> 1.2-dev and noticing significant memory savings, around 30%. Geir
> pointed out that it probably wouldn't be that much...
> 
> When I review that in the light of the above discussion of the
> Introspector issues, I think the increased memory usage had to do with
> the fact that, every once in a while, I would deploy new beans into my
> applications. Since my servlet detects that, loads the new classes and
> creates new instance of objects (beans), it seems that the old
> classes/methods would still be referenced in the Introspector and
> ClassMap of Velocity, so they'd just 'hang around' indefinitely, thus
> increasing memory usage.
> 
> So, the deployment of 1.2-dev probably had very little to do with memory
> usage apart from the fact that the whole JVM was restarted and therefore
> references to all those old beans were gone as well. In other words
> memory usage probably dropped because all those caches were cleaned out.

Sure - what are you seeing now that a few weeks have gone by?

> 
> I've checked my servlet and where it's referencing the beans, classes
> and methods I'm loading and here are the findings:
> 
> - class objects are referenced only from local variables, so when the
> method is finished executing, those class objects are ready for garbage
> collection
> - beans/methods are referenced as Hashtable values; the Hashtables are
> stored into ServletContext or HttpSession as attributes - so unless
> Tomcat has some major bugs in that area, when a session is gone, so
> should be the attribute and the Hashtable values with it; as for
> ServletContext, the attributes holding Hashtables are removed with every
> reload of the application and the actual bean objects are keyed by
> names, so new bean is always replacing an existing value - it is never
> added
> - the other source of memory leaks could be Tomcat's classloader - if
> it's hanging to previously loaded class objects - I don't know all that
> much about the mechanisms in Tomcat to comment
> 
> That's what leads me to believe that memory savings I saw were result of
> the initial condition where memory leaks didn't yet occur, rather then
> actual memory savings.
> 
> So, unless there are some horrible performance penalties in using Weak*
> thingies, I'm all for it. Actually, I'd be more then happy to give
> feedback once the patch becomes available.

I have been playing with Attila's idea of switching to strings vs. Classes
for the introspector map, and I think all will be well.

What I think should happen is that we don't get fancy, but just dump the
introspector cache once we notice something is amiss - that way we aren't
trying to guess what the classloader is doing now, or in the future.  It's
unsettling to assume what might be going on...

Since this is something that will happen infrequently, relatively speaking,
then the penalty of refreshing the introspection information is small (and
the piece of mind is large :)

While playing with it, I remembered one small 'separate instance' fix I need
to do before 1.2.  After that (and I want to run it by Attila to make sure
it is what he was thinking ) then I have what I think is a simple
implementation of his clever idea...  There is no complexity cost or
algorithm change, so I think it will be safe to put in 1.2.

geir


-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
Bojan Smojver wrote:
> 
> Attila Szegedi wrote:
> >
> > ----- Original Message -----
> > From: "Geir Magnusson Jr." <ge...@optonline.net>
> > To: <ve...@jakarta.apache.org>
> > Sent: 2001. szeptember 7. 0:03
> > Subject: Re: performance questions
> >
> > >
> > > I am not sure what happens with Tomcat's classloader when you load a new
> > > jar.  I would think that if it's just your servlet, then the Velocity
> > stuff
> > > wouldn't need to change.  The template cache will hold what it has.  The
> > > introspector might accumulate gunk over time, but I wouldn't think that
> > > would be significant amounts of memory.  I assume that the JAR only
> > contains
> > > code?
> > >
> >
> > Introspector holds a strong reference to Class objects, so it prevents them
> > from being unloaded. This way, not only does it accumulate method cache
> > information, but it also keeps those classes around together with their code
> > and every object reachable from their static fields. And that can impose a
> > significant memory leak in an environment where classes are reloaded
> > frequently.
> >
> > This could be fixed with employment of weak references and removal of
> > superfluous strong references:
> > - using WeakHashMap instead of Hashtable for Introspector.classMethodMaps
> > - removing the clazz field from ClassMap (it could be passed on as a
> > parameter from constructor to populateMethodCache(), and no other method
> > references it). This is worth doing regardless of other suggestions.
> > - using WeakReference containing Method as values in ClassMap.methodCache
> > - using WeakReference containing Method as elements of list stored in
> > MethodMap.methodByNameMap
> >
> > If people are comfortable with these changes, I can do them.
> > Attila.
> 
> This is really great stuff! I think I'm seeing memory leaks in my
> servlet for exactly the same reason (I'm also loading classes, doing
> introspection etc.).
> 
> Thanks heaps!
> 
> Bojan

If you remember, a few weeks ago I posted a message about switching to
1.2-dev and noticing significant memory savings, around 30%. Geir
pointed out that it probably wouldn't be that much...

When I review that in the light of the above discussion of the
Introspector issues, I think the increased memory usage had to do with
the fact that, every once in a while, I would deploy new beans into my
applications. Since my servlet detects that, loads the new classes and
creates new instance of objects (beans), it seems that the old
classes/methods would still be referenced in the Introspector and
ClassMap of Velocity, so they'd just 'hang around' indefinitely, thus
increasing memory usage.

So, the deployment of 1.2-dev probably had very little to do with memory
usage apart from the fact that the whole JVM was restarted and therefore
references to all those old beans were gone as well. In other words
memory usage probably dropped because all those caches were cleaned out.

I've checked my servlet and where it's referencing the beans, classes
and methods I'm loading and here are the findings:

- class objects are referenced only from local variables, so when the
method is finished executing, those class objects are ready for garbage
collection
- beans/methods are referenced as Hashtable values; the Hashtables are
stored into ServletContext or HttpSession as attributes - so unless
Tomcat has some major bugs in that area, when a session is gone, so
should be the attribute and the Hashtable values with it; as for
ServletContext, the attributes holding Hashtables are removed with every
reload of the application and the actual bean objects are keyed by
names, so new bean is always replacing an existing value - it is never
added
- the other source of memory leaks could be Tomcat's classloader - if
it's hanging to previously loaded class objects - I don't know all that
much about the mechanisms in Tomcat to comment

That's what leads me to believe that memory savings I saw were result of
the initial condition where memory leaks didn't yet occur, rather then
actual memory savings.

So, unless there are some horrible performance penalties in using Weak*
thingies, I'm all for it. Actually, I'd be more then happy to give
feedback once the patch becomes available.

Bojan

Re: performance questions

Posted by Bojan Smojver <bo...@binarix.com>.
Attila Szegedi wrote:
> 
> ----- Original Message -----
> From: "Geir Magnusson Jr." <ge...@optonline.net>
> To: <ve...@jakarta.apache.org>
> Sent: 2001. szeptember 7. 0:03
> Subject: Re: performance questions
> 
> >
> > I am not sure what happens with Tomcat's classloader when you load a new
> > jar.  I would think that if it's just your servlet, then the Velocity
> stuff
> > wouldn't need to change.  The template cache will hold what it has.  The
> > introspector might accumulate gunk over time, but I wouldn't think that
> > would be significant amounts of memory.  I assume that the JAR only
> contains
> > code?
> >
> 
> Introspector holds a strong reference to Class objects, so it prevents them
> from being unloaded. This way, not only does it accumulate method cache
> information, but it also keeps those classes around together with their code
> and every object reachable from their static fields. And that can impose a
> significant memory leak in an environment where classes are reloaded
> frequently.
> 
> This could be fixed with employment of weak references and removal of
> superfluous strong references:
> - using WeakHashMap instead of Hashtable for Introspector.classMethodMaps
> - removing the clazz field from ClassMap (it could be passed on as a
> parameter from constructor to populateMethodCache(), and no other method
> references it). This is worth doing regardless of other suggestions.
> - using WeakReference containing Method as values in ClassMap.methodCache
> - using WeakReference containing Method as elements of list stored in
> MethodMap.methodByNameMap
> 
> If people are comfortable with these changes, I can do them.
> Attila.

This is really great stuff! I think I'm seeing memory leaks in my
servlet for exactly the same reason (I'm also loading classes, doing
introspection etc.).

Thanks heaps!

Bojan

Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/7/01 12:31 PM, "Attila Szegedi" <sz...@freemail.hu> wrote:

> 
> ----- Original Message -----
> From: "Geir Magnusson Jr." <ge...@optonline.net>
> To: <ve...@jakarta.apache.org>
> Sent: Friday, September 07, 2001 8:41 PM
> Subject: Re: performance questions
> 
> 
>> 
>> Cool.  I am very interested in doing this with you - this subject is
>> something I have had long on my list for mastering, and if you don't mind,
> I
>> would love to do this with you, or do it with you 'looking over my
>> shoulder'.
>> 
> 
> No problem. I'm a little bit in a shortage of free time (having my second
> kid born two weeks ago;

CONGRATULATIONS!!!

> helping the wife around the house, keeping the
> bigger kid (2 yrs old) from scraping down the place,

I understand that's a perfectly easy age to manage :)

> getting up at night to
> the little one, etc.) however I'll try to be around. The basic idea is that
> whenever you hold onto a Method or Class object, you do it through a
> WeakReference. When the Method or the Class is in a hashmap key, you only
> have to use WeakHashMap instead of ordinary HashMap/Hashtable. When the
> Method or the Class is in a hashmap value or in an ordinary field, you have
> to replace it with WeakReference, and store the Method or the Class as the
> reference of the WeakReference.

Ok - that's what I figured - I just haven't worked with
Weak(Hashmap|Reference) before.  Will holler.
 
> 
>> Certainly #2 is a good one - I will stare at that today on the beach (I
> have
>> summoned the courage to bring my new iBook out to the pool anyway - not to
>> the beach yet...)
>> 
> 
> <sigh>Not been to beach since last October.</sigh> But at least that was
> Tunisia then.

This is our first vacation in years, and is making us realize we need to
relax a bit more.  It took us 4 whole days before we began relaxing.  It's a
very weird state I find myself in, this relaxed.  It's almost unhealthy :)

I dream to visit Tunisia.

:)

geir

>> geir
>> 
> 
> Attila.
> 
> 

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Attila Szegedi <sz...@freemail.hu>.
----- Original Message -----
From: "Geir Magnusson Jr." <ge...@optonline.net>
To: <ve...@jakarta.apache.org>
Sent: Friday, September 07, 2001 8:41 PM
Subject: Re: performance questions


>
> Cool.  I am very interested in doing this with you - this subject is
> something I have had long on my list for mastering, and if you don't mind,
I
> would love to do this with you, or do it with you 'looking over my
> shoulder'.
>

No problem. I'm a little bit in a shortage of free time (having my second
kid born two weeks ago; helping the wife around the house, keeping the
bigger kid (2 yrs old) from scraping down the place, getting up at night to
the little one, etc.) however I'll try to be around. The basic idea is that
whenever you hold onto a Method or Class object, you do it through a
WeakReference. When the Method or the Class is in a hashmap key, you only
have to use WeakHashMap instead of ordinary HashMap/Hashtable. When the
Method or the Class is in a hashmap value or in an ordinary field, you have
to replace it with WeakReference, and store the Method or the Class as the
reference of the WeakReference.


> Certainly #2 is a good one - I will stare at that today on the beach (I
have
> summoned the courage to bring my new iBook out to the pool anyway - not to
> the beach yet...)
>

<sigh>Not been to beach since last October.</sigh> But at least that was
Tunisia then.
> geir
>

Attila.



Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/7/01 12:57 AM, "Attila Szegedi" <sz...@freemail.hu> wrote:

> 
> ----- Original Message -----
> From: "Geir Magnusson Jr." <ge...@optonline.net>
> To: <ve...@jakarta.apache.org>
> Sent: 2001. szeptember 7. 0:03
> Subject: Re: performance questions
> 
> 
>> 
>> I am not sure what happens with Tomcat's classloader when you load a new
>> jar.  I would think that if it's just your servlet, then the Velocity
> stuff
>> wouldn't need to change.  The template cache will hold what it has.  The
>> introspector might accumulate gunk over time, but I wouldn't think that
>> would be significant amounts of memory.  I assume that the JAR only
> contains
>> code?
>> 
> 
> Introspector holds a strong reference to Class objects, so it prevents them
> from being unloaded. This way, not only does it accumulate method cache
> information, but it also keeps those classes around together with their code
> and every object reachable from their static fields. And that can impose a
> significant memory leak in an environment where classes are reloaded
> frequently.
> 
> This could be fixed with employment of weak references and removal of
> superfluous strong references:
> - using WeakHashMap instead of Hashtable for Introspector.classMethodMaps
> - removing the clazz field from ClassMap (it could be passed on as a
> parameter from constructor to populateMethodCache(), and no other method
> references it). This is worth doing regardless of other suggestions.
> - using WeakReference containing Method as values in ClassMap.methodCache
> - using WeakReference containing Method as elements of list stored in
> MethodMap.methodByNameMap
> 
> If people are comfortable with these changes, I can do them.
> Attila.
> 
> 

Cool.  I am very interested in doing this with you - this subject is
something I have had long on my list for mastering, and if you don't mind, I
would love to do this with you, or do it with you 'looking over my
shoulder'.

Certainly #2 is a good one - I will stare at that today on the beach (I have
summoned the courage to bring my new iBook out to the pool anyway - not to
the beach yet...)

geir


-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Lane Sharman <la...@san.rr.com>.
> ... (I believe you but tend to prove things to
> myself...),

I would like the confirmation, geir, because it was really scary when I saw the
component timing. I had to double-check this a couple of times with brian before we
confirmed this was true.

We have a synthetic performance test for wm throughput and the Total Elapsed Time
doubled when SoftReferences were employed.

(Throughput as a measure of TET is under concurrent load, not single-threaded
load).

-lane



Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/8/01 12:08 PM, "Attila Szegedi" <sz...@freemail.hu> wrote:

> I think I have a satisfying solution on topic of Velocity caching
> interference with class reloading that does not need weak references nor
> waterlevel strategy:
> 
> - Introspector could use qualified class names instead of Class object as
> keys in Introspector.classMethodMaps. We could keep the clazz field in
> ClassMap, and on each access compare by == the stored clazz value and the
> actual clazz in calling method (which have equal qualified names). If
> they're not the same Class object, we should assume there was class
> reloading, and throw away the existing ClassMap. We could further improve
> this by throwing away all ClassMaps that store class information for same
> class loader the originally thrown ClassMap's clazz belonged to.
> 
> I'll implement this shortly.

I wonder if the simplest way then would be to dump the entire classmap at
that point and let it rebuild - because you have to dump all.  It's a bit
excessive, but keeps the code simpler, and this is to solve what isn't
supposed to be a common occurrence.

I am going to see if I can get this to work...

geir



-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Attila Szegedi <sz...@freemail.hu>.
I think I have a satisfying solution on topic of Velocity caching
interference with class reloading that does not need weak references nor
waterlevel strategy:

- Introspector could use qualified class names instead of Class object as
keys in Introspector.classMethodMaps. We could keep the clazz field in
ClassMap, and on each access compare by == the stored clazz value and the
actual clazz in calling method (which have equal qualified names). If
they're not the same Class object, we should assume there was class
reloading, and throw away the existing ClassMap. We could further improve
this by throwing away all ClassMaps that store class information for same
class loader the originally thrown ClassMap's clazz belonged to.

I'll implement this shortly.

Attila.

Re: performance questions

Posted by Attila Szegedi <sz...@freemail.hu>.
Yes, I'm also aware of the fact that

----- Original Message -----
From: "Geir Magnusson Jr." <ge...@optonline.net>
To: <ve...@jakarta.apache.org>
Sent: Saturday, September 08, 2001 1:54 AM
Subject: Re: performance questions


>
> This is good feedback.  We are less worried about a performance (speed)
> improvement than a memory improvement, but certainly something we want to
> keep in mind.
>
> If this is indeed true (I believe you but tend to prove things to
> myself...), then this is a place where we have to be very careful - speed
is
> of the essence.
>

Yes, it indeed is. I think we could come up with a design where the use of
references could be turned on or off through setting a Velocity property.
This way, people could turn it on only if their applicaion involves frequent
class reloads. Alternatively, maybe using a low water - high water caching
strategy is the way to go. This will need some more thinking.

> We can see if we can incrementally do this - I think the suggestion of not
> holding onto Class references will help, so that things can be cleaned up
> when reloaded.  This is what started this.

This solely won't help. As long as you hold a Method object, you also hold
the class, its class loader and all other classes loaded through it. How
about accessing class B through a Method object of class A:

Method methodOfA = ...;
Class classB = Class.forName("B",
methodOfA.getDeclaringClass().getClassLoader());


 Attila.




Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/7/01 12:58 PM, "Lane Sharman" <la...@san.rr.com> wrote:

>> 
>>>> 
>>>> This could be fixed with employment of weak references and removal of
>>>> superfluous strong references:
> 
> I would avoid using weak references as a performance improvement (you are
> distinguishing here between WeakReference and SoftReference in java.lang.ref,
> right?).
> 
> The access speed is really slow compared to a normal object reference. We
> tested
> this a while back with WM and made these types of  References optional as a
> result. It added 50% more time to some performance benchmarks which tested
> soley
> the cache manager. The time spent synchronizing access is largish and so
> threads
> wait a long time waiting to defreference a soft reference.
> 

This is good feedback.  We are less worried about a performance (speed)
improvement than a memory improvement, but certainly something we want to
keep in mind.

If this is indeed true (I believe you but tend to prove things to
myself...), then this is a place where we have to be very careful - speed is
of the essence. 

We can see if we can incrementally do this - I think the suggestion of not
holding onto Class references will help, so that things can be cleaned up
when reloaded.  This is what started this.

geir

> There is a space/time/cost performance equation with tracking small objects no
> longer used so they can be garbage collected. So, one has to be careful that
> in
> running an LRU algorithm, you don't end up costing more processor time than
> the
> resultant benefit. One algorithm I have worked with with goes something like
> this.
> It is coarse but cpu gentle:
> 
> Inside the cache manager:
>   a) obtain  a memory low water mark and a high water mark (parameters)
>   b) if memory usage is below the low water mark do nothing
>   c) when memory gets above the low water mark, allocate a fixed queue of size
> M(another parameter)
>   to contain recent objects referenced
>   d) when memory usage gets above the high water mark it is time to adjust the
> cache:
>         a) remove every object in the cache that is not in the queue;
>         b) deallocate the queue as well.
>         c) run the gc.
> 
> This is an algorithm that is a variant on one for vm page thrashing. The
> implementation of the queue is not trivial if you track duplicates _and_ do
> not
> want the algorithm to be either in and of itself a memory or cpu monster in
> its
> own right :).
> 
> java.util.LinkedList is not a bad place to start a subclass if you want to
> track
> duplicates and thus maintain an LRU list although there are a number of
> variants
> of LRU in the cs literature.
> 
> -lane
> 
> 

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Lane Sharman <la...@san.rr.com>.
>
> >>
> >> This could be fixed with employment of weak references and removal of
> >> superfluous strong references:

I would avoid using weak references as a performance improvement (you are
distinguishing here between WeakReference and SoftReference in java.lang.ref,
right?).

The access speed is really slow compared to a normal object reference. We tested
this a while back with WM and made these types of  References optional as a
result. It added 50% more time to some performance benchmarks which tested soley
the cache manager. The time spent synchronizing access is largish and so threads
wait a long time waiting to defreference a soft reference.

There is a space/time/cost performance equation with tracking small objects no
longer used so they can be garbage collected. So, one has to be careful that in
running an LRU algorithm, you don't end up costing more processor time than the
resultant benefit. One algorithm I have worked with with goes something like this.
It is coarse but cpu gentle:

Inside the cache manager:
    a) obtain  a memory low water mark and a high water mark (parameters)
    b) if memory usage is below the low water mark do nothing
    c) when memory gets above the low water mark, allocate a fixed queue of size
M(another parameter)
    to contain recent objects referenced
    d) when memory usage gets above the high water mark it is time to adjust the
cache:
          a) remove every object in the cache that is not in the queue;
          b) deallocate the queue as well.
          c) run the gc.

This is an algorithm that is a variant on one for vm page thrashing. The
implementation of the queue is not trivial if you track duplicates _and_ do not
want the algorithm to be either in and of itself a memory or cpu monster in its
own right :).

java.util.LinkedList is not a bad place to start a subclass if you want to track
duplicates and thus maintain an LRU list although there are a number of variants
of LRU in the cs literature.

-lane



Re: performance questions

Posted by Jason van Zyl <jv...@apache.org>.
On 9/7/01 2:08 PM, "Geir Magnusson Jr." <ge...@optonline.net> wrote:

> 
> Good stuff, but I think we should push this into 1.3.  We are very close to
> rolling 1.2

Sounds good. I'd like to 1.2 into turbine 2.2 so a release would be good.
 
> geir

-- 

jvz.

Jason van Zyl

http://tambora.zenplex.org
http://jakarta.apache.org/turbine
http://jakarta.apache.org/velocity
http://jakarta.apache.org/alexandria
http://jakarta.apache.org/commons



Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/7/01 4:13 AM, "Jason van Zyl" <jv...@apache.org> wrote:

> On 9/7/01 6:57 AM, "Attila Szegedi" <sz...@freemail.hu> wrote:
> 
>> 
>> ----- Original Message -----
>> From: "Geir Magnusson Jr." <ge...@optonline.net>
>> To: <ve...@jakarta.apache.org>
>> Sent: 2001. szeptember 7. 0:03
>> Subject: Re: performance questions
>> 
>> 
>>> 
>>> I am not sure what happens with Tomcat's classloader when you load a new
>>> jar.  I would think that if it's just your servlet, then the Velocity
>> stuff
>>> wouldn't need to change.  The template cache will hold what it has.  The
>>> introspector might accumulate gunk over time, but I wouldn't think that
>>> would be significant amounts of memory.  I assume that the JAR only
>> contains
>>> code?
>>> 
>> 
>> Introspector holds a strong reference to Class objects, so it prevents them
>> from being unloaded. This way, not only does it accumulate method cache
>> information, but it also keeps those classes around together with their code
>> and every object reachable from their static fields. And that can impose a
>> significant memory leak in an environment where classes are reloaded
>> frequently.
>> 
>> This could be fixed with employment of weak references and removal of
>> superfluous strong references:
>> - using WeakHashMap instead of Hashtable for Introspector.classMethodMaps
>> - removing the clazz field from ClassMap (it could be passed on as a
>> parameter from constructor to populateMethodCache(), and no other method
>> references it). This is worth doing regardless of other suggestions.
>> - using WeakReference containing Method as values in ClassMap.methodCache
>> - using WeakReference containing Method as elements of list stored in
>> MethodMap.methodByNameMap
>> 
>> If people are comfortable with these changes, I can do them.
> 
> Sure, send a patch and I'll apply it to the introspector. Also if you see
> any way of using a standard introspector that would be great. I've always
> wanted to remove that code but never got around to it.
> 
> If you make changes and the testbed passes than the changes are fine with
> me. Do you think you could come up with test that demonstrates the problem
> in the first place and than show that it is corrected by your changes?


Good stuff, but I think we should push this into 1.3.  We are very close to
rolling 1.2

geir

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
Developing for the web?  See http://jakarta.apache.org/velocity/
If you look up, there are no limits - Japanese Proverb


Re: performance questions

Posted by Jason van Zyl <jv...@apache.org>.
On 9/7/01 6:57 AM, "Attila Szegedi" <sz...@freemail.hu> wrote:

> 
> ----- Original Message -----
> From: "Geir Magnusson Jr." <ge...@optonline.net>
> To: <ve...@jakarta.apache.org>
> Sent: 2001. szeptember 7. 0:03
> Subject: Re: performance questions
> 
> 
>> 
>> I am not sure what happens with Tomcat's classloader when you load a new
>> jar.  I would think that if it's just your servlet, then the Velocity
> stuff
>> wouldn't need to change.  The template cache will hold what it has.  The
>> introspector might accumulate gunk over time, but I wouldn't think that
>> would be significant amounts of memory.  I assume that the JAR only
> contains
>> code?
>> 
> 
> Introspector holds a strong reference to Class objects, so it prevents them
> from being unloaded. This way, not only does it accumulate method cache
> information, but it also keeps those classes around together with their code
> and every object reachable from their static fields. And that can impose a
> significant memory leak in an environment where classes are reloaded
> frequently.
> 
> This could be fixed with employment of weak references and removal of
> superfluous strong references:
> - using WeakHashMap instead of Hashtable for Introspector.classMethodMaps
> - removing the clazz field from ClassMap (it could be passed on as a
> parameter from constructor to populateMethodCache(), and no other method
> references it). This is worth doing regardless of other suggestions.
> - using WeakReference containing Method as values in ClassMap.methodCache
> - using WeakReference containing Method as elements of list stored in
> MethodMap.methodByNameMap
> 
> If people are comfortable with these changes, I can do them.

Sure, send a patch and I'll apply it to the introspector. Also if you see
any way of using a standard introspector that would be great. I've always
wanted to remove that code but never got around to it.

If you make changes and the testbed passes than the changes are fine with
me. Do you think you could come up with test that demonstrates the problem
in the first place and than show that it is corrected by your changes?

> Attila.
> 
> 

-- 

jvz.

Jason van Zyl

http://tambora.zenplex.org
http://jakarta.apache.org/turbine
http://jakarta.apache.org/velocity
http://jakarta.apache.org/alexandria
http://jakarta.apache.org/commons



Re: performance questions

Posted by Attila Szegedi <sz...@freemail.hu>.
----- Original Message -----
From: "Geir Magnusson Jr." <ge...@optonline.net>
To: <ve...@jakarta.apache.org>
Sent: 2001. szeptember 7. 0:03
Subject: Re: performance questions


>
> I am not sure what happens with Tomcat's classloader when you load a new
> jar.  I would think that if it's just your servlet, then the Velocity
stuff
> wouldn't need to change.  The template cache will hold what it has.  The
> introspector might accumulate gunk over time, but I wouldn't think that
> would be significant amounts of memory.  I assume that the JAR only
contains
> code?
>

Introspector holds a strong reference to Class objects, so it prevents them
from being unloaded. This way, not only does it accumulate method cache
information, but it also keeps those classes around together with their code
and every object reachable from their static fields. And that can impose a
significant memory leak in an environment where classes are reloaded
frequently.

This could be fixed with employment of weak references and removal of
superfluous strong references:
- using WeakHashMap instead of Hashtable for Introspector.classMethodMaps
- removing the clazz field from ClassMap (it could be passed on as a
parameter from constructor to populateMethodCache(), and no other method
references it). This is worth doing regardless of other suggestions.
- using WeakReference containing Method as values in ClassMap.methodCache
- using WeakReference containing Method as elements of list stored in
MethodMap.methodByNameMap

If people are comfortable with these changes, I can do them.
Attila.


Re: performance questions

Posted by Tim Joyce <ti...@hoop.co.uk>.
Will,


> Thanks for the quick response.  Yes, my JAR has only code.  And no, I only
> have 6 or 7 VMs.
>
> Must be something else.  I'll keep playing around.

I would give optomise it http://www.vmgear.com/ a whirl (free evaluation).
I had a similar problem yesterday, optomise it ran happily on the production
server and let me monitor java memory usage with a local client.  it's easy
to set up.

cheers

timj




RE: performance questions

Posted by Will Glass-Husain <wg...@forio.com>.
Thanks for the quick response.  Yes, my JAR has only code.  And no, I only
have 6 or 7 VMs.

Must be something else.  I'll keep playing around.

Best, WILL

-----Original Message-----
From: Geir Magnusson Jr. [mailto:geirm@optonline.net]
Sent: Thursday, September 06, 2001 3:04 PM
To: velocity-user@jakarta.apache.org
Subject: Re: performance questions


On 9/6/01 5:26 PM, "Will Glass-Husain" <wg...@forio.com> wrote:

> Hi,
>
> I'm seeing my servlet memory usage climb over time (with a fairly small
user
> base), and wondering if Velocity could be playing a role.  I'm using a
> subclass of VelocityServlet, (velocity version 1.2-dev) on Apache Tomcat
> 3.2.3.
>
> (1) Every time I upload a new JAR file with my servlet, my memory usage
goes
> up significantly.  Could there be some type of memory "leak" with either
the
> template cache or introspection?  (I've read the note in the Developer's
> Guide on this and have turned caching on).

I am not sure what happens with Tomcat's classloader when you load a new
jar.  I would think that if it's just your servlet, then the Velocity stuff
wouldn't need to change.  The template cache will hold what it has.  The
introspector might accumulate gunk over time, but I wouldn't think that
would be significant amounts of memory.  I assume that the JAR only contains
code?

>
> One hypothesis I have is that the Velocity singleton may be accumulating
> unnecessary info when the Tomcat classloader reloads my JAR file.  Any
ideas
> on this?
>
> (2) Going to new pages increases the memory usage.  Does the template
cache
> ever clear?

No - that is something we want to put in for the case where you have a large
content site (say thousands of articles that are #include()-ed into the
page)  For normal use, it shouldn't matter because  it stores by resource
name, so if you reload the same page, the new AST will replace the old one.

> A note on my configuration.  I have no file "velocity.properties".
Instead,
> I call the following code in the "loadConfiguration" method of my servlet.
> (appended to the end of this message).  Not sure if this affects the
memory
> issue.
>
> Appreciate any ideas.
>
> Thanks, WILL
>
> ******
> final public Properties loadConfiguration(ServletConfig cfg) {
> Properties p;
>
> p = new Properties();
>
> p.setProperty("file.resource.loader.path",
> getInitParameter("TemplatePath"));
> p.setProperty("fileresource.loader.cache","true");
> p.setProperty("velocimacro.library","macro_library.fml");
> p.setProperty("velocimacro.permissions.allow.inline.local.scope","true");
> p.setProperty("runtime.log.invalid.references ","false");
> p.setProperty("resource.manager.logwhenfound","false");
> p.setProperty("runtime.log.logsystem.class",
> "com.forio.servlet.ForioLogger");
>
> return p;
> }
>

Everything looks fine here.  Do you need local scope for VMs?  That would
add to memory usage, but unless you went VM-crazy, it shouldn't be of major
significance...

geir



Re: performance questions

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 9/6/01 5:26 PM, "Will Glass-Husain" <wg...@forio.com> wrote:

> Hi,
> 
> I'm seeing my servlet memory usage climb over time (with a fairly small user
> base), and wondering if Velocity could be playing a role.  I'm using a
> subclass of VelocityServlet, (velocity version 1.2-dev) on Apache Tomcat
> 3.2.3.
> 
> (1) Every time I upload a new JAR file with my servlet, my memory usage goes
> up significantly.  Could there be some type of memory "leak" with either the
> template cache or introspection?  (I've read the note in the Developer's
> Guide on this and have turned caching on).

I am not sure what happens with Tomcat's classloader when you load a new
jar.  I would think that if it's just your servlet, then the Velocity stuff
wouldn't need to change.  The template cache will hold what it has.  The
introspector might accumulate gunk over time, but I wouldn't think that
would be significant amounts of memory.  I assume that the JAR only contains
code?

> 
> One hypothesis I have is that the Velocity singleton may be accumulating
> unnecessary info when the Tomcat classloader reloads my JAR file.  Any ideas
> on this?
> 
> (2) Going to new pages increases the memory usage.  Does the template cache
> ever clear?

No - that is something we want to put in for the case where you have a large
content site (say thousands of articles that are #include()-ed into the
page)  For normal use, it shouldn't matter because  it stores by resource
name, so if you reload the same page, the new AST will replace the old one.
 
> A note on my configuration.  I have no file "velocity.properties".  Instead,
> I call the following code in the "loadConfiguration" method of my servlet.
> (appended to the end of this message).  Not sure if this affects the memory
> issue.
> 
> Appreciate any ideas.
> 
> Thanks, WILL
> 
> ******
> final public Properties loadConfiguration(ServletConfig cfg) {
> Properties p;
> 
> p = new Properties();
> 
> p.setProperty("file.resource.loader.path",
> getInitParameter("TemplatePath"));
> p.setProperty("fileresource.loader.cache","true");
> p.setProperty("velocimacro.library","macro_library.fml");
> p.setProperty("velocimacro.permissions.allow.inline.local.scope","true");
> p.setProperty("runtime.log.invalid.references ","false");
> p.setProperty("resource.manager.logwhenfound","false");
> p.setProperty("runtime.log.logsystem.class",
> "com.forio.servlet.ForioLogger");
> 
> return p;
> }
> 

Everything looks fine here.  Do you need local scope for VMs?  That would
add to memory usage, but unless you went VM-crazy, it shouldn't be of major
significance...

geir