tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Rainer Jung <>
Subject More Caching for WebappClassLoader?
Date Tue, 10 Jan 2012 10:43:55 GMT
I analyzed a fun problem a few weeks ago. Someone was using the shared 
loader extensively (TC 5.5). They observed performance problems and 
thread dumps showed, that often the class loader locking was the culprit.

Code was inside loadClass(). Now it turned out, it wasn't about really 
loading classes. Instead there was a lot of deserialization going on 
(data received from a backend app server). Deserialization uses 
reflection intensively and reflection leads to loadClass() calls to 
retrieve the classes. We observed e.g. several hundreds loadClass() 
calls per second.

Now loadClass() in the WebappClasLoader does:

- check own class cache
- check super class cache
- try loading from system loader
- call Class.forName with parent loader (which calls loadClass() there)
   [only if "delegated", which is *not* the default]
- try loading via findClass()
- call Class.forName with parent loader (which calls loadClass() there)
   [only if not "delegated", which *is* the default]

So if a class was previously loaded by the shared loader (or common or 
server), then we will not find in in our own or the super cache, will 
then *always* try to load it via system, will then (if default) always 
try to load it ourselves and only finally will try to load it via parent 
and find it there in the cache.

This turned out to become a bottleneck.

I implemented a quick hack which cached the classes loaded by system, 
parent and shared positively and negatively (not found) in the 
WebappLoader using the same method that was already used for its own 
cache. Thus the massive calls to those loaders could be avoided and the 
bottleneck went away.

I wonder whether we want to improve caching in the WebappLoader. Of 
course most deployments no longer use shared or common to share many 
application classes, but it is still a supported feature and for some 
classes like JDBC it is standard.

What we could do to keep the design simple is caching any positive 
result from loadClass() in the WebappLoader, even it it was found via 
super, system or parent. In addition we could also cache negative 
results for all those. The biggest downsides I can see would be

- less dynamics: if someone had a more dynamic loader unerneath ours, 
which would change the result of loadClass() during runtime, we would 
shield the app from it, because we now return classes from our cache.

- increased memory use for the cache, i.e. the list of class names and 
references to the classes.

To stay completely compatible I think the feature should not be default, 
at least until TC 7, maybe switch default for 8.

What do you think? Does it make sense? Should I prepare a patch for trunk?



To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message