If you are developing a web-application that runs on Tomcat 7, it is highly likely that you will encounter a PermGen space error on Tomcat which happens when you deploy and undeploy the application several times and there is a memory leak. There could be several reasons for a memory leak and they could stem from loading third-party jars such as JDBC drivers and logger jars from within the web-application lib. To overcome some of these potential issues, it is best to
load them directly into Tomcat lib and let Tomcat the
Driver Manager take care of de-registering them when not in use.
While the best approach to dealing with this problems and other memory related problems is debugging the cause of the memory leak and fixing it, there are times when tuning the JVM parameters can alleviate the cause and improve performance of the application to a certain extent.
Before diving into the tuning the JVM parameters, it is important to understand how JVM organises its memory space and what is the difference between
heap and permgen space and how they are used.
This article gives a very good overview of the JVM memory layout. To summarise the difference between the two, the
permgen space is used to store classes loaded by the class loader, primitives,any static classes and other JVM related data. On the other hand, the
heap space is mainly used to store objects created by the application. It is further divided as explained
here into
Eden, Survivor and Tenured Gen space.
It is also important to note that since Java 1.6 update 16, there have been some major
changes to the process used to compute heap size in 32 bit and 64 bit JVMs and in client / server mode.
Having understood the basics of JVM memory organisation, we can look at tuning Tomcat's memory allocation for its
heap and
permgen. While there are several parameters that can be used for
tuning the JVM, this post is just going to describe the minimum and maximum parameters for specifying the
heap and the
permgen space. The location of where to specify these parameters and their values depends on your machine specification (operating system, memory size, 32 bit or 64 bit) and how you invoke Tomcat.
Deciding on the actual values of the parameters should be taken after monitoring the JVM using some tools such as
jVisualVM. The values given below are sample values that worked in my particular case.
Case 1: Tomcat is invoked from within Eclipse on a 32 bit machine.
Specs : Tomcat 7.0.28, Eclipse Juno, Sun Java 1.6.30, Windows 7.0
The parameters should be specified in Server Launch Configuration -> Open Launch Configuration -> Edit Launch Configuration Properties ->Arguments
|
Tomcat Launch Configuration in Eclipse |
The detailed steps are available
here.
Case 2: Tomcat is invoked via its start up script on a 32 bit virtual machine.
Specs : Tomcat 7.0.28, Sun Java 1.6.30, Ubuntu 12.04
Create a
setenv.sh file and add the following one line in it.
export JAVA_OPTS="-Dfile.encoding=UTF-8 -server -Xms128m -Xmx256m -XX:MaxPermSize=128m -XX:+DisableExplicitGC"
Transfer this file to your
Tomcat/bin directory and re-start Tomcat.
There are a number of ways of verifying that the JVM parameters were applied to Tomcat. The easiest way on Ubuntu is :
ps -ef | grep tomcat
You should see something similar to the line below:
john 17841 1 5 15:23 pts/0 00:00:09 /usr/bin/java -
Djava.util.logging.config.file=/usr/local/apache-tomcat/conf/logging.properties -Xms128m -Xmx256m -XX:MaxPermSize=128m -XX:+DisableExplicitGC -
Djava.endorsed.dirs=/usr/local/apache-tomcat/endorsed -classpath /usr/local/apache-tomcat/bin/bootstrap.jar:/usr/local/apache-tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/apache-tomcat -Dcatalina.home=/usr/local/apache-tomcat -Djava.io.tmpdir=/usr/local/apache-tomcat/temp org.apache.catalina.startup.Bootstrap start
With respect to parameter values for the heap, it is important to note that :
(Managed Heap + native heap + (thread stack size * number of threads)) cannot exceed 2GB on 32bit x86 Windows or Linux systems (ref)
2GB is a
theoretical limit. Since the heap requires contiguous memory space, it might be hard to push the heap beyond 1.4GB on a 32 bit Windows machine.
A final comment.
The JVM is an intelligent software and has several inbuilt processes built into it that work to optimize its performance. Attempting to tune the JVM may not always result in a performance improvement. Tuning the JVM is dependent on the machine specification, the design decisions taken behind the architecture of the web-application it is hosting, the number of applications hosted by the JVM and when all else fails, Trial and Error.