|
Graeme, 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 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. I'm still investigation this but its proving very hard to track down. The fix for 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 Graeme, 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. 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. Here, I get problem just with ehcache jar. All other files have been deleted. My setup: Grails 1.0.4 hi there, if you can provide one, I can help 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 Hi, I wonder if these tips help: "Memory leaks where the classloader cannot be garbage collected" Two pointers from this article: 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. 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. 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. 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 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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