Ubuntu – Tomcat Excessive Memory Consumption

javatomcatUbuntu

I have a fresh server running Ubuntu 11.04 (Natty) (64-bit). I started off by installing openjdk and tomcat6. When the Tomcat server starts up, it immediately uses 480+ MB of memory. This seems way out of proportion and I'm wondering if anyone has a solution to get Tomcat to use 200-300 MB (or less) memory.

I used memtop to see this: (Note: I removed all but the large entries. The 499MB entry is Tomcat)

  user@xyz:~# python memtop-0.9.py
  PID |   private/writ. mem |command
      |  current | previous |(truncated)
19776 | 499.3 MB |    +++++ |/usr/lib/jvm/java-6-openjdk/bin/java-Djava.util.logging.config.file=/var/lib/tomcat6/conf/logging.properties-Djava.awt.headless=true-Xm
18082 | 148.6 MB |    +++++ |/usr/sbin/mysqld
 1385 |   3.6 MB |    ++    |pythonmemtop-0.9.py
RAM usage:  ==============================================  69.3 %

Furthermore, you can see what JDK and Tomcat packages I have installed:

user@xyz:~# dpkg --get-selections | grep jdk
default-jdk                                     install
openjdk-6-jdk                                   install
openjdk-6-jre                                   install
openjdk-6-jre-headless                          install
openjdk-6-jre-lib                               install

user@xyz:~# dpkg --get-selections | grep tomcat
libtomcat6-java                                 install
tomcat6                                         install
tomcat6-admin                                   install
tomcat6-common                                  install
tomcat6-user                                    install

The startup script for Tomcat sets Xmx to 128M:

JAVA_OPTS="-Djava.awt.headless=true -Xmx128M"

Does anyone have any ideas on what I could do to knock the memory consumption down to something more reasonable? I do not understand why the JVM and Tomcat together would need to consume this much memory.

EDITS

For the heck of it, I downloaded Tomcat 6 directly and ran the startup script. Keep in mind that no Xmx value was set this time. When running this, memtop shows that Tomcat is using 737 MB's worth of memory!

This leads me to believe that there is an issue with openjdk using a serious amount of memory for the JVM.


I tried the same thing with a fresh .zip download of Tomcat 7 — same issue. It was using 740 MB of memory.


I installed the Sun JRE/JDK. Memory consumption dropped to around 400 MB (down from almost 500 MB). This is still more memory usage than what I would prefer!

(sun-java6-bin, sun-java6-jdk, sun-java6-jre)


When I run top, I get this:

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
13749 tomcat6   20   0  481m  68m 9892 S    0  7.4   0:02.85 java

I realize and expect that a 64-bit machine/JVM will use more memory, but I did not expect it to be this high. I'm running on a VM that is only guaranteeing me 512MB.

Best Answer

---- Edited to provide example as the point isn't coming across ----

A process launches and asks for 1 GB of memory.

That process then starts eight threads (which all have access to the allocated 1 GB of memory).

Someone runs a tool to determine how much memory is being used. The tool works as follows:

  1. Find every scheduleable item (each thread).
  2. See how much memory it can access.
  3. Add that memory together
  4. Report the sum.

The tool will report that the process is using 9 GB of memory, when it is (hopefully) obvious that there are eight spawned threads (and the thread for the original process) all using the same GB of memory.

It's a defect in how some tools report memory; however, it is not an easily fixable defect (as fixing it would require changing the output of some very old (but important) tools). I don't want to be the guy who rewrites top or ps, it would make the OS non-POSIX.

---- Original post follows ---- Some versions of memory reporting tools (like top) mistakenly confuse threads (which all have access to the same memory) with processes. As a result, a tomcat instance that spawns five threads will misreport it's memory consumption by five times.

The only way to make sure is to list out the processes with their memory consumption individually, and then read the memory for one of the threads (that is getting listed like a process). That way you know the true memory consumption of the application. If you rely on tools that do the addition for you, you will overestimate the amount of memory actually used by the number of threads referencing the same shared memory.

I've had boxes with 2 GB of memory (and 1 GB of swap) reporting that ~7GB of memory was in use on a particularly thread heavy application before.

For a better understanding of how memory is reported by many tools, look here. If they python code is parsing the text of one of these tools, or obtaining that data from the same system calls, then it is subject to the same errors in over reporting memory.