Issue Details (XML | Word | Printable)

Key: GRAILS-2544
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Graeme Rocher
Reporter: InterZ
Votes: 20
Watchers: 20
Operations

If you were logged in you would be able to see more operations.
Grails

Stopping Tomcat Context and doing undeploy does not completely shut down app, grails jars still locked

Created: 27/Feb/08 04:36 PM   Updated: 11/Sep/09 08:58 AM   Resolved: 11/Sep/09 08:58 AM
Return to search
Component/s: Project infrastructure
Affects Version/s: 1.0.1
Fix Version/s: 1.2-M3

Time Tracking:
Not Specified

Environment: Grails 1.0.1 - Windows - Tomcat 6
Issue Links:
Duplicate
 
Related
 


 Description  « Hide

Hi,
We have a grails app that is being tested on tomcat 6.

We have a META-INF/context.xml defined in our WAR file. We start tomcat and deploy this WAR via the manager interface to the root context. The WAR is deployed OK and the app runs great. We then go into the tomcat manager and do a "STOP" on the context.

Noticed this output in the tomcat STDOUT
log4j:ERROR LogMananger.repositorySelector was null likely due to error in class reloading, using NOPLoggerRepository.

Secondly, we then do a tomcat "undeploy" which deletes all the deployed context files. When this is completed, the following Grails jars are left in the <contextRoot>/WEB-INF/lib directory. Because of this you cannot re-deploy your WAR again unless you kill the entire tomcat process to delete the jars. Maybe something in grails' ServletContextListener is not properly handling a shutdown and releasing resources?

grails-cli-1.0.1.jar
*-core.1.0.1.jar
*-crud-1.0.1.jar
*-gorm-1.0.1.jar
*-spring-1.0.1.jar
*-web-1.0.1.jar
*-webflow-1.0.1.jar



InterZ added a comment - 27/Feb/08 04:40 PM

also this occurs if either of the following are defined in your context

antiJARLocking="true"
antiResourceLocking="true"

Setting to false allows a re-deploy, however over time you will run out of memory as resources are not being properly released by the app


InterZ added a comment - 18/Mar/08 05:17 PM

Graeme,
Does grails have any classes that have static members that reference instances of things in the system? Such as

private static Object x = <some object created during runtime>

And if so are these being released during a shutdown call, such as in a hot deployment in a container? I have gone through my app after reading this article http://blogs.sun.com/fkieviet/entry/classloader_leaks_the_dreaded_java to cleanup alot of these things in my code.

I have tomcat permgen space set = ~256m and am able to get maybe 10-15 hot deployments under tomcat. However I eventually do run out of permgen space. I am wondering if grails has any similar issues.


Graeme Rocher added a comment - 30/May/08 06:50 AM

I'm still investigation this but its proving very hard to track down. The fix for GRAILS-2687 seemed to eliminate the log4j error on mac and linux, but it still occurs in Windows. Also I am able to deploy and undeploy fine in Mac or Linux but the file locking issues exists in Windows.

I am now deep in profiler land and it seems the container or spring or grails is holding onto references to Grails plugins and classes. Why I don't know at this stage within GrailsContextLoader we have code that clears out all static references to Grails code so I'm at a loss as to why this is happening but will keep digging


InterZ added a comment - 30/May/08 09:47 AM

Graeme,
Haven't looked at this in a bout 2 months now, however what I ended up finding is that you may just be running into classes outside of your control which are retaining references to Grails Classes. For example in our app, we registered a bouncy castle JCE provider with SecurityManager, even after de-registering it on shutdown, the JVM SecurityManager STILL retains a reference to the BouncyCastle CLASS. Since that class is also referenced by the Tomcat WebAppClassloader, every Class used in our app is retained in the permgen. Short of rewriting SecurityManager there was not much we could do. The best we could do is cleanup all static references to instances retained in the app, to reduce permgen usage. Assume that Classes will be retained in the stale webappclassloader and work from there to reduce the impact.

You may be running into simular issues. Using that "jhat" tool is the best way to figure things out though.

Also searching around on permgen issues on the net, will turn up lists of known offenders in the JVM and other libraries, some of which grails may use.


Peter Ledbrook added a comment - 02/Jun/08 03:48 AM

A lot of work has been done on this already, but we would like to get 1.0.3 out soon so we're moving the remainder of the issue to 1.0.4.


Marcos Silva Pereira added a comment - 29/Nov/08 12:54 PM

Here, I get problem just with ehcache jar. All other files have been deleted. My setup:

Grails 1.0.4
Tomcat 6.0.18
jdk 1.5.0_16
Windows 2003 Server


Filip Hanik added a comment - 25/Mar/09 11:48 AM

hi there,
if you attach a WAR file that gets the class retention issue on the reload I could push for a fix/workaround in Tomcat, assuming there is one.
In tomcat there are already many work arounds for faulty libs, but we don't have all of them taken care of. We lack reproducible cases.

if you can provide one, I can help


John Allison added a comment - 25/Mar/09 05:18 PM

Here's a log4j mailing list post that might be about this. The reference bugs and the bugs they reference might be the problem, i.e. not particularly a grails bug? HTH

http://marc.info/?l=log4j-user&m=120897082320333&w=2


Lari Hotari added a comment - 02/Apr/09 03:08 PM

Hi,

I wonder if these tips help:

"Memory leaks where the classloader cannot be garbage collected"
http://opensource.atlassian.com/confluence/spring/pages/viewpage.action?pageId=2669

Two pointers from this article:
http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/web/util/IntrospectorCleanupListener.html
(cleans JavaBeans Intropector cache, might not be required on Java 1.5.0)

There's a solution for freeing references to JDBC drivers loaded from the webapp's classloader:

// code written by Guillaume Poirier
public class CleanupListener implements ServletContextListener { 
  public void contextInitialized(ServletContextEvent event) { 
  } 
  public void contextDestroyed(ServletContextEvent event) { 
    try { 
      Introspector.flushCaches(); 
      for (Enumeration e = DriverManager.getDrivers(); e.hasMoreElements();) { 
        Driver driver = (Driver) e.nextElement(); 
        if (driver.getClass().getClassLoader() == getClass().getClassLoader()) { 
          DriverManager.deregisterDriver(driver);          
        } 
      } 
    } catch (Throwable e) { 
      System.err.println("Failled to cleanup ClassLoader for webapp"); 
      e.printStackTrace(); 
    } 
  } 
}

(code written by Guillaume Poirier)

I think Grails needs the DriverManager.deregisterDriver solution since JDBC drivers are commonly loaded from the webapp classloader.


Mark Thomas added a comment - 29/Jun/09 06:21 PM

I have done some analysis with YourKit and Grails running on Tomcat. Grails does indeed need to clean up its JDBC drivers. Note that the classloader test in the code example above is unnecessary since DriverManager.getDrivers() will only return the Driver instances loaded by the webapp.

Grails uses ThreadLocals in org.codehaus.groovy.grails.documentation.DocumentationContext. These also need to be cleaned up. As a general rule for webapps, a ThreadLocal should not exist beyond the life of a individual request else memory leaks will follow.

Finally, there is a log4j bug that I discovered (not yet reported) where loading a config file from a jar will lock the jar. The workaround is to place your log4j config file in WEB-INF/classes, rather than inside a JAR in WEB-INF/lib

As an aside, I fixed Tomcat's JDBC driver clean-up code and I have some really ugly ThreadLocal clean-up code that I'll commit to Tomcat trunk once I have a chance to clean it up.


Graeme Rocher added a comment - 14/Jul/09 09:31 AM

I have implemented the DriverManager change, cleaned up the ThreadLocal code that we have in Grails, and removed the log4j.properties file from the WAR deployment. Hopefully, with the next Grails 1.2 milestone and Tomcat release this issue can be closed.


Graeme Rocher added a comment - 11/Sep/09 08:58 AM

Tested against Grails 1.2 SNAPSHOT and Tomcat 6.0.20 with -Dorg.apache.catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES=false and no errors occur on undeployment

closing issue