11 January 2006

Object Life Time Monitoring

Two years ago, in the dark ages before Java 5 (2004) I needed to do some Java profiling of the Herold website. Recent investigations using commercial profilers like JProbe had failed because their memory and CPU needs made the application virtually unresponsive. So I had to come up with some lightweight profiling solution of my own.

I was only concerned with memory consumption, as performance seemed to be bottle-necked by garbage collection. Based on a method described by Jack Shirazi in his book, I used PhantomReferences and a modified java.lang.Object to track object creation and garbage collection. That's all, very lightweight. Using this (Object) Life Time Monitor (LTM) I got an idea of the number of certain class instances created and active over time. A simple graphical viewer gave an overview of the collected data, the instances' life times, something like that:

Total number of life instances over timeInstallation
Download LTM 1.01 (49 KB), together with source. It's JDK 1.3 compliant and does not depend on any other libraries. To use it with Java 1.4 extract the ltm-*.zip and put the LTM.jar into your bootclasspath. When using other JREs than 1.4, you have to modify your java.lang.Object as shown below and put it before LTM.jar into your bootclasspath.
// --- code added to object ---
public Object() {
if (at.herold.test.objlifetime.MonitoringFlag.monitoring) {
at.herold.test.objlifetime.ObjectLifetimeMonitoring.monitor(this);
}
}
// --- code added to object ---
Usage
Start your application with LTM enabled by
java -Xbootclasspath/p:LTM.jar
-cp <your application's classpath>
at.herold.test.objlifetime.ObjectLifetimeMonitoring
s
<your application's main class>
<your application's parameters if any>
Tell LTM to start collecting data with java -jar LTM.jar start on the same machine running the application. This enables the counting of objects. To stop collecting data run java -jar LTM.jar stop. The application will continue to run normally.

To save the recently collected raw data use java -jar LTM.jar save. This saves the raw data using a constant file name. The file is created in the current folder, depending on your start routines this might be windows/system32 or somewhere else. Now you may stop the application. You can view the saved data with java -jar LTMViewer.jar <raw file>. This loads, analyses and displays the object lifetime statistics. <raw file> is the file saved by LTM earlier. An JPG image is saved as well.

SourceSt. Monans Cemetery
In case you want to add or change something, there are the following Java packages: objlifetime contains the LTM core classes. Monitoring is managed by the AdminThread, which listens to a socket for commands. objlifetime.viewer contains the viewer to analyse the saved data from the LTM. Analysing classes are subclasses of LifeTimeAnalyser. The source is described in detail in the article Überwachung der Anzahl aktiver Objekte in JavaSPEKTRUM, 1/2006. LTM is Open Source under the GPL license.

FAQ
Q: When defining my own java.lang.Object where do I take it's implementation from? A: The original Object shipped with JDK is used. It's source can be found in the src.zip of the JDK. You just have to compile the new Object.java and put in in the bootclasspath before the LTM.jar (because it contains 1.4 Object.class already).

Q: What is all this 'bootclasspath' about? A: See Using the BootClasspath.

Q: Which type of file has to be passed as an argument to LTM? I am running this application by calling the Main.main() method and it's expecting a file name. A: The application is started as usual, LTM just has to sit in its bootclasspath. So <your application> is the qualified class name of the application you want to start for monitoring, e.g. com.company.app.Main. If you want to test a Tomcat web application you need to use the Catalina Bootstrap class here, as found in startup.sh/bat.

Words of Warning
LTM is a simplistic, very specialised kind of profiler. It was written in 2004 targeting J2SE 1.4. Professional profiling tools are much more powerful and reliable. LTM was only developed because we could not suffer the overhead of a full blown memory snapshot algorithm. Note that the newer Java 5 offers better ways to collect the memory information either by using JMX or agents and JVMTI.

References(List of all my publications with abstracts.)

10 comments:

Radek said...

Hello,

I tried your program, but it did not run and wrote some informations as

Exception in thread "main" java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:310)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:176)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:163)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:381)
at java.net.Socket.connect(Socket.java:537)
at java.net.Socket.connect(Socket.java:487)
at java.net.Socket.(Socket.java:384)
at java.net.Socket.(Socket.java:198)
at at.herold.test.objlifetime.AdminThread.main(Unknown Source)

I use java
version "1.6.0_0"
OpenJDK Runtime Environment (build 1.6.0_0-b11)
OpenJDK Client VM (build 1.6.0_0-b11, mixed mode, sharing)

but a tried on another platform and it wrote same Excaption.

Do you know what is wrong.

Thank you very much.

Peter Kofler said...

Dear Radek, thank you for your comment. I just noticed that the documentation is incomplete. To start the application using LTM, you have to start it through LTM, so the AdminThread is listening for your commands later. I updated the Usage section:

java -Xbootclasspath/p:LTM.jar
     -cp <your application's classpath>
     at.herold.test.objlifetime.ObjectLifetimeMonitoring
     s
     <your application's main class>
     <your application's parameters if any>

Let me know if this helps.
Regards

Radek said...

Hello, I tried it again by this procedure : I changed my working directory to ~/NetBeansProjects/OperaceSMaticemi/build/classes and I start my program by : java operacesmaticemi.Main and it is running.

then I tried program LTM by command from my BASH in the same directory :
java -Xbootclasspath/p:LTM.jar -cp operacesmaticemi.Main at.herold.test.objlifetime.ObjectLifetimeMonitoring s Main , but it wrote to my stdout

LTM error in Application Starter
java.lang.ClassNotFoundException: Main
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:323)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
at at.herold.test.objlifetime.ObjectLifetimeMonitoring.main(Unknown Source)

Before it all i copied LTM.jar to my bootclasspath of java - /usr/lib/jvm/java-6-openjdk/jre/lib/

Sorry, if i do some stupid thing as typied wrong classpath but i tried other possibilities and it wrote same Exceptions. Sorry that my English is not good but I am from Czech republic and I try study English more.

Thank you very much for your advices.

Radek

Peter Kofler said...

No problem, sure we'll get it working for your scenario.

Assuming that you are in the classes folder of your project (~/.../classes) then you would have to use these values:

<your application's classpath> = .
<your application's main class> = operacesmaticemi.Main
(Remember always to use full qualified class names.)

So use the following command line:

java -Xbootclasspath/p:/usr/lib/jvm/java-6-openjdk/jre/lib/LTM.jar
     -cp .
     at.herold.test.objlifetime.ObjectLifetimeMonitoring
     s
     operacesmaticemi.Main

Even if you put LTM.jar into jre/lib, it's not in the boot classpath. You have to set it in the command line.

Hope this helps,
regards

Radek said...

It is running Thank you, much for your speed and good advices. Your program helped me much.

Peter Kofler said...

You're welcome. I'm happy my code was put to good use again ;-)

Cheers

Radek said...

Hello, would I ask, where in your program ensure, that your program doesn't catchs objects from your program, but only objects from tested program ?

Thank you very much for your advice.

Radek

Peter Kofler said...

It's done in ObjectLifetimeMonitoring. At beginning of the monitor method it's
MonitoringFlag.monitoring = false;
and at the end again
MonitoringFlag.monitoring = true;

Radek said...

Yes, but i dont understand, how you enasures, that your program dont call metod

at.herold.test.objlifetime.ObjectLifetimeMonitoring.monitor(this);

in Object.java on your objects, in your program ?

Thanks

Peter Kofler said...

The modified Object checks MonitoringFlag.monitoring inside the constructor if to call the monitor method. See the code fragment with
// --- code added to object ---
above.