I am also experiencing this problem in a webapp.  My understanding of
Tomcat classloading if as follows, please correct if wrong.

Tomcat has a shared ClassLoader that can load up classes that all
webapps can use.  This ClassLoader will never be GCed as it lives for
the lifetime of the Tomcat process.

Tomcat creates a ClassLoader per webapp when it is deployed.  If the
webapp is undeployed Tomcat releases the ClassLoader.  At this point the
ClassLoader, it's Classes and all object instances of these classes
should become GCable and be collected sometime in the future.


Using Sun's 1.5.0_06 JDK if I set the max perm gen size to about 30MB
the apps deploys fine the first time and then dies with OutOfMemory:
PermSpace on a redeploy.  I if set the perm gen to 64MB (the sun
default) then it takes about 4/5 redeploys before the OOM.

My hibernate SessionFactory is held in a static variable of a class so I
can access it from wherever in want in my application.  My understanding
is that the static will get cleaned up when the webapp redeploys and
releases the ClassLoader that created it, so I don't *think* this is the
problem.


I read somewhere that apache-commons logging stores cached references to
Classes/ClassLoaders in a static map.  Sure enough it does in the code
of LogFactory and a call to LogFactory.releaseAll() will clean this
cache out, but even with this call in the contextDestroyed of a
ServletContextListener there was no obvious change in the behaviour,
still got a perm space error as above.

I did some debugging into the LogFactory to see what was happening, I
saw the following behaviour.

1) Deploy Webapp
2) Call to LogFactory.cacheFactory() to store a
ClassLoader(1)->LogFactory mapping in LogFactory.factoryCache
3) Undeploy Webapp
4) Call to LogFactory.releaseAll() from my
ServletContextListener.contextDestroyed(). LogFactory.factoryCache is
cleaned out.
5) Call to LogFactory.cacheFactory() AGAIN (see stack trace below)
storing ClassLoader(1)->LogFactory again.
6) Redeploy Webapp.
7) Call to LogFactory.cacheFactory() (factoryCache is empty) storing
ClassLoader(2)->LogFactory

Note the numbering of the ClassLoaders to indicate different instances.
The first ClassLoader gets put back in the LogFactory cache after I
clean it out manually.

Here's the stacktrace from the call to LogFactory.cacheFactory()

java.lang.Exception: Stack trace
        at java.lang.Thread.dumpStack(Thread.java:1158)
        at
org.apache.commons.logging.LogFactory.cacheFactory(LogFactory.java:497)
        at
org.apache.commons.logging.LogFactory.getFactory(LogFactory.java:323)
        at
org.apache.commons.logging.LogFactory.getLog(LogFactory.java:351)
        at
org.hibernate.cache.ReadOnlyCache.<clinit>(ReadOnlyCache.java:16)
        at sun.misc.Unsafe.ensureClassInitialized(Native Method)
        at
sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(UnsafeFieldAcces
sorFactory.java:25)
        at
sun.reflect.ReflectionFactory.newFieldAccessor(ReflectionFactory.java:12
2)
        at java.lang.reflect.Field.acquireFieldAccessor(Field.java:917)
        at java.lang.reflect.Field.getFieldAccessor(Field.java:898)
        at java.lang.reflect.Field.get(Field.java:357)
        at
org.apache.catalina.loader.WebappClassLoader.clearReferences(WebappClass
Loader.java:1607)
        at
org.apache.catalina.loader.WebappClassLoader.stop(WebappClassLoader.java
:1491)
        at
org.apache.catalina.loader.WebappLoader.stop(WebappLoader.java:706)
        at
org.apache.catalina.core.StandardContext.stop(StandardContext.java:4535)
        at
org.apache.catalina.core.ContainerBase.removeChild(ContainerBase.java:89
2)
        at
org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:10
34)
        at
org.apache.catalina.startup.HostConfig.check(HostConfig.java:1202)
        at
org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:29
2)
        at
org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSu
pport.java:119)
        at
org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.j
ava:1305)
        at
org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.proc
essChildren(ContainerBase.java:1569)
        at
org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.proc
essChildren(ContainerBase.java:1578)
        at
org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(
ContainerBase.java:1558)
        at java.lang.Thread.run(Thread.java:595)


Looks like during the WebappClassLoader cleanup the logging is being
reinitialised.  I've reached my limit of knowledge on ClassLoaders and
tomcat but I'm not sure why it would be doing a class initialisation
when it's trying to cleanup the class loader.  I'm not sure if this
definitely my problem,  maybe someone who's more familiar with
ClassLoading issues can make something of this.

Cheers.


-----Original Message-----
From: Caldarale, Charles R [mailto:[EMAIL PROTECTED] 
Sent: 28 November 2006 16:43
To: Tomcat Users List
Subject: RE: Memory leaks on webapp redeploy

> From: Christopher Schultz [mailto:[EMAIL PROTECTED]
> Subject: Re: Memory leaks on webapp redeploy
> 
> Maybe this issue has been fixed in recent VMs (IIRC, older VMs -- 
> maybe 1.3-era -- would never discard java.lang.Class objects.

Not true either.  I've been porting Sun's JVMs to various platforms
since 1.2, and GC of classes has always been available (not sure about
1.1).

> Java 1.5 has the "-Xnoclassgc" option

That's also been around since at least 1.3.

> For instance, if you had a singleton with a static instance of the 
> class, but no references to the Class object, no instances other than 
> the singleton (a reasonable assumption for a singleton), and no 
> outside references to the singleton object, then the VM is within it's

> rights to discard both the instance and the Class since they are 
> "unused". I seem to recall this being a problem for folks who thought 
> that singletons were a good idea, and so the Java folks decided to
keep
> Class objects around forever.

The first part is true, the latter conclusion isn't, at least not in
Sun-based JVMs.  You do have to be careful if only reflection is used to
access a class, since it can disappear as you described.

> Or am I just crazy and making the whole thing up? ;)

Always a possibility, especially in this business :-)

 - Chuck


THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY
MATERIAL and is thus for use only by the intended recipient. If you
received this in error, please contact the sender and delete the e-mail
and its attachments from all computers.

---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org To unsubscribe,
e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



 This e-mail is bound by the terms and conditions described at 
http://www.subexazure.com/mail-disclaimer.html


---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to