Unstable Terrain

Software development in the real world

Java Reflection Api: More Drawbacks

with one comment

Vinay wrote on DZone about the Java Reflection API and mentioned some drawbacks. Here’s one he missed:

The Reflection API Loads Classes as a Side-Effect

I encountered an error message recently in the Tomcat application I currently develop. I upgraded Log4J to 1.2.15 and suddenly, I was unable to stop Tomcat cleanly.

log4j:ERROR LogMananger.repositorySelector was null likely due to error in class reloading, using NOPLoggerRepository.

I found mention of this error in Log4J Bug 43867, but it turns out that the error lies inside Tomcat instead, and is due to the way that Tomcat unloads classes when WARs are undeployed. But to understand the bug, a short intro on class loading is in order.

Classloading 100

Classes are loaded in multiple stages. The main reason for this is to decrease program startup time and avoid using memory until the class is actually used.

The three stages of classloading are:

  1. Loading
  2. Linking
  3. Initialising

and only then is the class instantiated. Classes tend to be linked fairly eagerly, but lazily initialised. (For more details, please see this TechJava article)

Back to the bug

When Tomcat unloads a WAR, it helpfully tries to compensate for bad programming inside the WAR by clearing out any static fields it can find. It’s a crude but effective way to dereference fields that might have strong references to stuff you are trying to unload.

Inside Tomcat, org.apache.catalina.loader.WebappClassLoader.clearReferences() triggers the bug
by overwriting all static variables in your webapp (classes and JARs) with null. It does this even with the standard Log4J LogFactory. However, getting the field of a class that hasn’t been initialised will cause it to be initialised, which instantiates all the static fields…. including those static fields which depend on LogFactory! Hilarity ensues.

Luckily, Log4J can detect when something (i.e. Tomcat) has pulled the rug out from underneath it and will substitute a NOPLoggerRepository which won’t do any logging but at least won’t throw Null Pointer Exceptions. It’s interesting to note that Log4J is often used in static fields, so in hindsight, this is obviously not the first time they’ve had to contend with this issue. At any rate, it spits out the error message, but Tomcat is still broken and the WAR unloading fails.

The Solution

The solution is fairly easy. First, Tomcat should make a list of all the fields it’s about to null out. This will trigger class instantiation on any class that hasn’t been completely loaded. Once this is complete, Tomcat can then null out the fields safely. Tomcat Bug 41059 has this fix, and you can expect it soon in Tomcat 6.0.21.

Advertisements

Written by Trent

October 27, 2009 at 9:00 am

One Response

Subscribe to comments with RSS.

  1. […] a comment » Changelog says that Bug 41059 has been fixed, meaning that tomcat won’t hang inconveniently when it tries to shut down. […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: