memory leak deploying web services caused by 
java.bean.Introspector.getBeanInfo()
---------------------------------------------------------------------------------

         Key: GERONIMO-1118
         URL: http://issues.apache.org/jira/browse/GERONIMO-1118
     Project: Geronimo
        Type: Bug
  Components: webservices  
    Versions: 1.0    
 Environment: Sun JDK 1.4.2/Win XP
    Reporter: Kevan Miller


If you deploy and undeploy DayTrader several times, your server will run out of 
Permanent Generation space. I've tracked down a problem which is caused by 
java.bean.Introspector (there may be other problems, but it's hard to tell 
until this problem is fixed). The basic problem is described here -- 
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5102804.

To summarize, the static method java.bean.Introspector.getBeanInfo(Class) 
computes a BeanInfo object to describe the given Class. The computed BeanInfo 
data is cached in a WeakHashMap called "beanInfoCache". There's one fatal flaw 
in this approach. There's nothing "weak" at all about beanInfoCache. The key 
for the Map is the Class object. The value object is the BeanInfo data. 
Unfortunately, the BeanInfo data strongly references the Class. This strong 
reference will prevent the Class from being identified as available for GC via 
the WeakHashMap.

Since java.bean.Introspector is loaded by the system class loader (and is thus 
a GC root), this means that Bean classes (e.g. 
org.apache.geronimo.samples.daytrader.client.ws.AccountDataBean), their 
MultiParentClassLoader, and all classes loaded by the MultiParentClassLoader 
will be kept alive until you kill your server...

Luckily (or because of this problem?), Introspector also has flushCaches() and 
flushFromCaches(Class) methods which perform predictable functions. Several 
projects, including Tomcat and Spring, use these methods to prevent 
Introspector from causing memory leaks in their environments.

Geronimo has the following usages of getBeanInfo()

axis-builder/src/java/org/apache/geronimo/axis/builder/HeavyweightTypeInfoBuilder.java:389
axis-builder/src/java/org/apache/geronimo/axis/builder/LightweightTypeInfoBuilder.java:131
service-builder/src/java/org/apache/geronimo/deployment/service/JavaBeanXmlAttributeBuilder.java:66

A non-scientific search (e.g. I don't have all the source), showed calls to 
Introspector.getBeanInfo() by the following projects:

axis, cglib, commons-collections, tomcat (but calls flushCache), log4j 

I've thought of the following options for fixing this problem (alternative 
proposals welcome):

1. Follow all calls to getBeanInfo(Class) with a flushFromCaches(Class). This 
seems fragile and impractical (we can't insure that other projects/apps follow 
this rule). 
2. Force java.Bean.Introspector to be loaded by MultiParentClassLoader. This 
would prevent the Introspector class from being a GC root. Would work, but is 
counter to the current class loader implementation...
3. Call Introspector.flushCaches() at appropriate times (i.e. when a 
ClassLoader is going out of scope -- when a GBean is stopped?). I need a little 
help here in knowing when/where this should be... Although this is a bit 
heavy-handed, it seems like a safe approach.
4. (just thought of this one). Instead of calling flushCaches() as described in 
3, we could instead loop through all classes loaded by the appropriate 
MultiParentClassLoaders and call flushFromCaches(Class) (or a subset of the 
classes). This would work, but doesn't seem necessary. I doubt we have very 
much caching going on...

I'll work on 3 and see how things improve...

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira

Reply via email to