In an earlier entry on "Advanced troubleshooting for Java exceptions", I covered how it was possible to generate dump data on Exceptions using -Xdump command line options. However the usual settings to generate dumps on exceptions:
-Xdump:where <dump type> is usually stack, java or system, causes a problem with ClassNotFoundExceptions as there are a number of these exceptions thrown during the normal running of an application, which are subsequently caught and handled by the application.:events=throw,range=1..1,filter=java/lang/ClassNotFoundException
The problem it causes...
For even the most simple application, a number of ClassNotFoundExceptions will be generated. The following test code:
public void createClassNotFoundException(){ MyClassLoader myLoader = new MyClassLoader(); try { myLoader.loadClass("MyClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } }where MyClassLoader is defined as:
private class MyClassLoader extends ClassLoader{ String myClassLoaderPath = System.getProperty("myloader.path"); public Class findClass (String name) throws ClassNotFoundException { if (myClassLoaderPath == null) myClassLoaderPath = new String("C:\\\\myhome\\classes\\"); File classFile = new File(myClassLoaderPath + name + ".class"); byte[] classBytes = null; try { FileInputStream fis = new FileInputStream(classFile); classBytes = new byte[(int)classFile.length()]; fis.read(classBytes); } catch (Exception e) { } if (classBytes != null) return defineClass(name, classBytes, 0, classBytes.length); else throw new ClassNotFoundException(name); } }Is designed to generate a ClassNotFoundException because there isn't a copy of "MyClass" in the path specified by "myloader.path" (or in c:\myhome\classes). However, if you run the test case with the standard -Xdump options from above:
-Xdump:stack:events=throw,range=1..1,filter=java/lang/ClassNotFoundExceptionYou actually get the following stack dump generated:
JVMDUMP006I Processing dump event "throw", detail "java/lang/ClassNotFoundException" - please wait. Thread=main (003951C4) Status=Running at java/lang/Class.forName(Ljava/lang/String;)Ljava/lang/Class; (Class.java:136) at com/ibm/jvm/Util.testRealtime()Z (Util.java:53) at com/ibm/jvm/Util.This is because there is some internal JVM logic which intentionally tries to load a class and then handles the ClassNotFoundException if the class is not present. In fact, there are a number of ClassNotFoundExceptions generated - in the running of the simple testcase there are a total of 6 generated, only the last of which is of interest to us.()V (Util.java:48) at java/lang/J9VMInternals.initializeImpl(Ljava/lang/Class;)V (Native Method) at java/lang/J9VMInternals.initialize(Ljava/lang/Class;)V (J9VMInternals.java:200) at java/lang/StringCoding. ()V (StringCoding.java:302) at java/lang/J9VMInternals.initializeImpl(Ljava/lang/Class;)V (Native Method) at java/lang/J9VMInternals.initialize(Ljava/lang/Class;)V (J9VMInternals.java:200) at java/lang/String.getBytes(Ljava/lang/String;)[B (String.java:645) at com/ibm/oti/util/Util. ()V (Util.java:20) at java/lang/J9VMInternals.initializeImpl(Ljava/lang/Class;)V (Native Method) at java/lang/J9VMInternals.initialize(Ljava/lang/Class;)V (J9VMInternals.java:200) at java/lang/System.getPropertyList()[Ljava/lang/String; (Native Method) at java/lang/System.ensureProperties()V (System.java:276) at java/lang/System. ()V (System.java:102) at java/lang/J9VMInternals.initializeImpl(Ljava/lang/Class;)V (Native Method) at java/lang/J9VMInternals.initialize(Ljava/lang/Class;)V (J9VMInternals.java:200) at java/lang/ClassLoader.initializeClassLoaders()V (ClassLoader.java:72) at java/lang/Thread.initialize(ZLjava/lang/ThreadGroup;Ljava/lang/Thread;)V (Thread.java:325) at java/lang/Thread. (Ljava/lang/String;Ljava/lang/Object;IZ)V (Thread.java:124) JVMDUMP013I Processed dump event "throw", detail "java/lang/ClassNotFoundException".
So, how do we filter to get the right ClassNotFoundException?
Filtering on the throwing method
The "filter" option of -Xdump does allow (as of 5.0 Service Refresh 9 and Java 6.0 Service Refresh 3) an additional level of filtering: on the method that is throwing the exception.
In our case above, the stack trace is:
java.lang.ClassNotFoundException: MyClass at com.ibm.test.exceptions.GenerateException$MyClassLoader.findClass(GenerateException.java:96) at java.lang.ClassLoader.loadClass(ClassLoader.java:643) at java.lang.ClassLoader.loadClass(ClassLoader.java:609) at com.ibm.test.exceptions.GenerateException.createClassNotFoundException(GenerateException.java:50) at com.ibm.test.exceptions.GenerateException.main(GenerateException.java:28)So adding additional filtering using the com.ibm.test.exceptions.GenerateException$MyClassLoader.findClass method should limit the number of dumps that are generated. This is done using a "hash" (#) separator in the filter argument followed by the method throwing the exception, eg. -Xdump:stack:events=throw,range=1..1,filter=java/lang/ClassNotFoundException#com/ibm/test/exceptions/GenerateException$MyClassLoader.findClass Which causes only the following output to be created:
JVMDUMP006I Processing dump event "throw", detail "java/lang/ClassNotFoundException" - please wait. Thread=main (0039525C) Status=Running at com/ibm/test/exceptions/GenerateException$MyClassLoader.findClass(Ljava/lang/String;)Ljava/lang/Class; (GenerateException.java:96) at java/lang/ClassLoader.loadClass(Ljava/lang/String;Z)Ljava/lang/Class; (ClassLoader.java:643) at java/lang/ClassLoader.loadClass(Ljava/lang/String;)Ljava/lang/Class; (ClassLoader.java:609) at com/ibm/test/exceptions/GenerateException.createClassNotFoundException()V (GenerateException.java:50) at com/ibm/test/exceptions/GenerateException.main([Ljava/lang/String;)V (GenerateException.java:28) JVMDUMP013I Processed dump event "throw", detail "java/lang/ClassNotFoundException".So this way we can generate dumps (stack, java or system) on the correct exception and go on to analyze the data in Memory Analyzer as before - which will give access to information on what, for example, the "myloader.path" system property is set to!