On Windows systems, an application may use getClass().getResource or getResourceAsStream methods to locate a resource inside the application, particularly in jar files that are in the application or accessible to it. If the streams remain open, subsequent attempts to redeploy or undeploy the application can fail. In addition, the Java runtime by default caches streams to jar files for performance reasons.
Be sure to close streams opened by your applications. Also, if an application needs to be redeployed or undeployed repeatedly, and also needs to obtain a resource from a jar file using getResource or getResourceAsStream, consider using getClass().getResource, which returns a URL object, then invoke the url.setUseCaches method to turn off caching for that jar file, and use url.getInputStream() to obtain the stream.
Although turning off caching for access to the jar file can slow performance, this approach does allow the application to be undeployed or redeployed. Note also that if the getClass().getResourceAsStream method is used instead, then the jar file in which the resource is located is cached (this is the default Java runtime setting) and remains open until the server is stopped.
Application servers such as GlassFish Server allow you to redeploy an application without restarting the server. Simply make the change in your source code, compile the source, and redeploy the application.
Each application is loaded using its own classloader. When you undeploy an application, its classloader is discarded with all the classes it loaded and is garbage collected sooner or later. However, if there's a reference from outside an application to an object in the application loaded by the application's classloader, that object can't be garbage collected. The reference holds the object in memory.
The memory in the Virtual Machine is divided into a number of regions. One of these regions is PermGen. It's an area of memory used to (among other things) load class files. The size of this memory region is fixed; it does not change when the VM is running. You can specify the size of this region with a command line switch: -XX:MaxPermSize. Setting the -Xmx parameter does not help: this parameter only specifies the total heap size and does not affect the size of the PermGen region.
If you keep loading new classes that can't be garbage collected because of references to them from outside the application, the VM runs out of space in the PermGen region, even if there's plenty of memory available. This is called a classloader leak. The resulting exception is java.lang.OutOfMemoryError: PermGen space.
The java.lang.String.intern() method also allocates memory in the PermGen region. If your application uses this method with strings and holds references to these strings, thereby making garbage collection impossible, your application may cause the same PermGen space exception.
Classloader leaks are difficult to diagnose. Most profilers list leaked objects but don't highlight the ones causing classloader leaks. Most profilers also stop tracing as soon as they reach a class object or classloader.
One diagnostic approach involves undeploying the application and triggering a memory dump using the JDK 6.0 jmap tool. Then you can use the JDK 6.0 jhat tool to analyze the dump. The simplest analysis is to list all instances of java.lang.Class and look for class objects that have many instances. This is a sign that the class has been loaded multiple times without being garbage collected.
If you're willing to modify the jhat code, you can perform more refined queries. For example:
Trace references to a classloader from all the instances of the classes it loaded.
Generate a list of all classloader instances that have loaded an identical set of classes.
Find classloader instances whose only strong-reference chains from the root set go through instances of classes loaded by those classloaders. These are called orphaned classloaders.
To override the original jhat code, put the JAR file of the modified jhat code in the lib/ext directory of the JDK.