You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Next »

How to Deal With Out Of Memory Errors

These errors are rather commonly seen during development phases, and even on production servers. These errors are even more annoying than others, because they do not show any stack trace. The reason for this is that a stack trace would not be of help for these errors. The code that fails with an Out Of Memory will be, in most cases, a "victim" of the problem, and not the problem itself.

Although it is very tempting to blame Tomcat on these errors, the fact is that many of them have their causes in "mistakes" in the webapps. These mistakes usually come from programming patterns and techniques perfectly legal and safe on standalone applications, but that are not correct in a managed environment like a servlet container (that is, Tomcat).

This page will maintain a list of those "well-known mistakes", so anyone experiencing these problems, or wanting to avoid them, could check their webapps and correct them.

The General Rule

The first thing to do is to set the basis for these patterns to be recognized. This way, the developer will be able to find even those mistakes that are not listed in this page, and why not, add them here (smile)

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.
  • 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.

This last case is the one we intend to address here. It is directly related to the fact that the webapp is running on a managed environment, in which code changes can be commited without the application being stopped at all.

Once said this, the patterns to be included here will be those that, although being safe and legal on a standalone application, need to be changed in some way to make them "compatible" with the servlet container.

The Singleton Pattern

This is a VERY used pattern in many java programs. It works safe and sound in any standalone application, and it looks something like:

public class MyClass {
  private static final MyClass instance = new MyClass();

  public static MyClass getInstance() {
    return instance;
  }

  private MyClass() { }
}

The problem with this pattern is that is created 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 class loader.

Workaround 1

This workaround is for the case this class should be shared between webapps. That is, we need to used the same instance across several webapps in the same server. 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.

There is not a problem in this case, because the class will be loaded by a parent classloader, and not by the webapp classloader itself, so no resources need to be reclaimed.

This is considered a workaround for the case in which your server has a single webapp. You can put your class, and all the classes it depends on, in the shared/classes directory, and it will not be a memory leak source anymore.

Workaround 2

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. 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.

  • No labels