Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Tomcat Wiki" for change 
notification.

The "OutOfMemory" page has been changed by markt.
The comment on this change is: Remove some nonsense. Replace it with more 
useful content..
http://wiki.apache.org/tomcat/OutOfMemory?action=diff&rev1=9&rev2=10

--------------------------------------------------

  An Out Of Memory can be thrown by several causes:
  
   * A servlet trying to load a several GBytes file into memory will surely 
kill the server. These kind of errors must be considered a simple bug in our 
program.
-  * To compensate for the data your servlet tries to load, you increase the 
heap size so that there is no room to create the stack size for the threads 
that need to be created.  Each thread takes 2M and in some OS's (like Debian 
Sarge) is not reducible with the -Xss parameter. 
[[http://goobsoft.homeip.net/Wiki.jsp?page=JavaDebianTuning|1]]  Rule of Thumb, 
use no more than 1G for heap space in a 32-bit web application.
+  * To compensate for the data your servlet tries to load, you increase the 
heap size so that there is no room to create the stack size for the threads 
that need to be created.  The memory required by each thread will vary by OS 
but can be as high as 2M by default and in some OS's (like Debian Sarge) is not 
reducible with the -Xss parameter. 
[[http://goobsoft.homeip.net/Wiki.jsp?page=JavaDebianTuning|1]]  Rule of Thumb, 
use no more than 1G for heap space in a 32-bit web application.
   * Deep recursive algorithms can also lead to Out Of Memory problems. In this 
case, the only fixes are increasing the thread stack size ({{{-Xss}}}), or 
refactoring the algorithms to reduce the depth, or the local data size per call.
   * A webapp that uses lots of libraries with many dependencies, or a server 
maintaining lots of webapps could exhauste the JVM PermGen space. This space is 
where the VM stores the classes and methods data. In those cases, the fix is to 
increase this size. The Sun VM has the flag {{{-XX:MaxPermSize}}} that allows 
to set its size (the default value is 64M)
   * Hard references to classes can prevent the garbage collector from 
reclaiming the memory allocated for them when a ClassLoader is discarded. This 
will occur on JSP recompilations, and webapps reloads. If these operations are 
common in a webapp having these kinds of problems, it will be a matter of time, 
until the PermGen space gets full and an Out Of Memory is thrown.
@@ -29, +29 @@

  
  == Threads ==
  
- No other threads started in the servlet must run. Otherwise they keep local 
variables, their classes and the whole class loader hard referenced.
+ Any threads a web application starts, a web application should stop. 
!ServletContextListener is your friend. Note Tomcat 7 will warn you if you do 
this and will also provide a (highly dangerous - use at your own risk) option 
to terminate the threads.
  
  == DriverManager ==
  
- If you load a java.sql.Driver in your own classloader (or servlets), the 
driver should be removed before undeploying. Each driver is registered in 
!DriverManager which is loaded in system classloader and references the local 
driver.
+ If you load a java.sql.Driver in your own classloader (or servlets), the 
driver should be removed before undeploying. Each driver is registered in 
!DriverManager which is loaded in system classloader and references the local 
driver. Note Tomcat will do this for you if you forget.
  
  {{{
                  Enumeration<Driver> drivers = DriverManager.getDrivers();
@@ -49, +49 @@

                  }
  }}}
  
- == The Singleton Pattern ==
+ == ThreadLocal ==
  
- This is a VERY used pattern in many java programs. It works safe and sound in 
any standalone application, and it looks something like:
+ The lifecycle of a !ThreadLocal should match that of a request. There is no 
guarantee that a thread will ever be used to process a request again so if a 
!ThreadLocal is left on the thread at the end of the request there may be no 
opportunity for the web application to clean it up. Note Tomcat 7 will do this 
for you.
  
+ == ContextClassLoader ==
- {{{
- public class MyClass {
-   private static final MyClass instance = new MyClass();
  
+ There are various parts of the Java API that retain a permanent reference to 
the context class loader. If this happens to be a web application class loader 
then a memory leak will occur. Tomcat provides 
[[http://svn.apache.org/repos/asf/tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java|workarounds]]
 for these where known but there are undoubtedly others.
-   public static MyClass getInstance() {
-     return instance;
-   }
  
+ == Logging Frameworks ==
-   private MyClass() { }
- }
- }}}
  
- The problem with this pattern is that it creates a hard reference to a class 
instance into the class itself. As long as this instance is not released, the 
class will not be unloadable. At the end, this leads to the server being unable 
to reclaim the space for the entire webapp class loader.
+ Most logging frameworks provide a mechanism to release all resources when you 
have finished with the framework. These should always be used in a container 
environment.
  
- Many of the workarounds below will sacrifice some of the virtues of the 
original pattern, for the sake of the server integrity. It is up to the 
designer/developer to decide whether these sacrifices are worth the benefits.
+ = When all else fails =
  
- === Validation ===
+ If you still have a leak then you'll need to debug the root cause. The 
outline of the process is:
+  1. You'll need a profiler (I use !YourKit), Tomcat and a copy of the app 
that leaks.
+  1. Configure Tomcat for use with the profiler. This usually means setting / 
adding to PATH and CATALINA_OPTS in setenv.(bat|sh)
+  1. Start Tomcat with the app deployed.
+  1. Reload the app once.
+  1. Start up the profiler and connected it to Tomcat.
+  1. Get a heap dump.
+  1. Look for instances of !WebappClassLoader. If there are more instances 
than you have apps deployed, you have a leak.
+  1. If there is a leak, there should be one extra instance of 
!WebappClassLoader.
+  1. Examine each of the !WebappClassLoader objects in turn to find the one 
where started==false.
+  1. Trace the GC roots of this object to find out what is holding on to a 
reference to that object that shouldn't be. That will be the source of the leak.
  
- Before you refactor your whole application, please ensure if this is really 
the problem. My singletons are definitely removed, but tomcat keeps crashing.
- 
-   1. Override method finalize in such a singleton class and put a 
System.out.println()-Message. 
-   2. In the constructor call several time System.gc() (because the garbage 
collector is a little bit lazy)
-   3. Redeploy the application several times
-   4. Probably you will see that the old singletons are definitely finalized 
which is only the case if the class loader is garbage collected.
-   5. After several redeployments an out of memory occures, even with one or 
two "singletons" in memory.
- 
- === Workaround 1: Move the class to another classloader ===
- 
- This workaround is for the case this class should be shared between webapps, 
or if the server will contain only one webapp. That is, we need to use the same 
instance across several webapps in the same server, or there is no need to 
worry about it. In this case, the class will need to be deployed on a shared 
classloader. This means this class must be in the {{{shared/lib}}} or 
{{{shared/classes}}} directory.
- 
- This way, the class will be loaded by a parent classloader, and not by the 
webapp classloader itself, so no resources need to be reclaimed on webapp 
reloadings.
- 
- This workaround may not always fit well with your code or design. In 
particular, care must be taken to avoid the singleton to keep references to 
classes loaded through the webapp classloader, because such references would 
prevent the classloader from being deallocated. A servlet context listener 
could be used to get rid of those references before the context is destroyed.
- 
- 
- === Workaround 2: Use commons-discovery ===
- 
- If you need to have a singleton instance for each webapp, you could use 
{{{commons-discovery}}}. This library provides a class named 
{{{DiscoverSingleton}}} that can be used to implement singletons in your webapp.
- 
- For using it, the class to be used as singleton will need to implement an 
interface (SPI) with the methods to be used. The following code is an example 
of usage of this library:
- 
- {{{
-   MyClass instance = DiscoverSingleton.find(MyClass.class, 
MyClassImpl.class.getName());
- }}}
- 
- It is important, for this library to work correctly, to not keep static 
references to the returned instances.
- 
- Just by using this syntax, you get the following advantages:
- 
-  * Any class could be used as a singleton, as long as it implements an SPI 
interface.
-  * Your singleton class has been converted into a replaceable component in 
your webapp, so you can "plug-in" a different implementation whenever you want.
- 
- But only this does not make for a workaround. The most important advantage is 
the {{{DiscoverSingleton.release()}}} method, that releases all references to 
instantiated singletons in the current classloader. A call to this method could 
be placed into a ServletContextListener, into its contextDestroyed() method.
- 
- That is, with a ServletContextListener simple implementation like the 
following:
- 
- {{{
- public class SingletonReleaser implements ServletContextListener {
-   public contextInitialized(ServletContextEvent event) { }
- 
-   public contextDestroyed(ServletContextEvent event) {
-     DiscoverSingleton.release();
-   }
- }
- }}}
- 
- we could release all cached references to the instantiated singletons. Of 
course, this listener should be registered on the web.xml descriptor before any 
other listener that could use a singleton.
- 
- 
- === Workaround 3: Use ServletContext attributes ===
- 
- This refactoring will work well provided the ServletContext instance is 
available, as a local variable or as a parameter.
- 
- It will be more efficient than using {{{commons-discovery}}}, but has the 
disadvantage of making your code depend on the web layer (ServletContext 
class). Anyway, I have found out that, in some cases, it is a reasonable 
approach.
- 
- There are many ways to do this refactoring, so I will just present one 
implementation that works well for me:
- 
-  * Create the following ServletContextListener:
- {{{
- public class SingletonFactory implements ServletContextListener {
-   public static final String MY_CLASS = "...";
- 
-   /**
-    * @see ServletContextListener#contextInitialized(ServletContextEvent)
-    */
-   public void contextInitialized(ServletContextEvent event) {
-     ServletContext ctx = event.getServletContext();
-     ctx.setAttribute(MY_CLASS, new MyClass());
-   }
- 
-   /**
-    * @see ServletContextListener#contextDestroyed(ServletContextEvent)
-    */
-   public void contextDestroyed(ServletContextEvent event) {
-     ctx.setAttribute(MY_CLASS, null);
-   }
- 
-   /**
-    * Optional method for getting the MyClass singleton instance.
-    */
-   public static MyClass getMyClassInstance(ServletContext ctx) {
-     return (MyClass)ctx.getAttribute(MY_CLASS);
-   }
- }
- }}}
-  * Register the listener in the web.xml descriptor
-  * Replace the calls to {{{MyClass.getInstance()}}} by:
- {{{
-   MyClass instance = (MyClass)ctx.getAttribute(SingletonFactory.MY_CLASS);
- 
-   /* or, if implemented:
-   MyClass instance = SingletonFactory.getMyClassInstance(ctx);
-   */
- }}}
- 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to