[jboss-cvs] JBossAS SVN: r61262 - trunk/testsuite/src/main/org/jboss/test/classloader/leak/clstore.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Sun Mar 11 00:38:02 EST 2007
Author: bstansberry at jboss.com
Date: 2007-03-11 00:38:02 -0500 (Sun, 11 Mar 2007)
New Revision: 61262
Added:
trunk/testsuite/src/main/org/jboss/test/classloader/leak/clstore/LeakAnalyzer.java
trunk/testsuite/src/main/org/jboss/test/classloader/leak/clstore/ReferenceReportNode.java
Log:
Support for condensed format classloader leak reports
Added: trunk/testsuite/src/main/org/jboss/test/classloader/leak/clstore/LeakAnalyzer.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/classloader/leak/clstore/LeakAnalyzer.java (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/classloader/leak/clstore/LeakAnalyzer.java 2007-03-11 05:38:02 UTC (rev 61262)
@@ -0,0 +1,430 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.test.classloader.leak.clstore;
+
+import java.io.CharArrayWriter;
+import java.io.PrintWriter;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.jboss.logging.Logger;
+import org.jboss.profiler.jvmti.JVMTICallBack;
+import org.jboss.profiler.jvmti.JVMTIInterface;
+import org.jboss.profiler.jvmti.ReferenceDataPoint;
+
+/**
+ * A LeakAnalyzer.
+ *
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1.1 $
+ */
+public class LeakAnalyzer extends JVMTIInterface
+{
+ private static final Logger log = Logger.getLogger(LeakAnalyzer.class);
+
+ /**
+ * Create a new LeakAnalyzer.
+ *
+ */
+ public LeakAnalyzer()
+ {
+ super();
+ }
+
+ /**
+ * Show the reference holders tree of an object. This returns a report you
+ * can visualize through MBean.
+ */
+ public String exploreObjectReferences(HashMap referencesMap, Object thatObject, int maxLevel, boolean useToString,
+ boolean condensed)
+ {
+ ReferenceReportNode root = new ReferenceReportNode(callToString(thatObject, useToString));
+
+ Set<ReferenceReportNode> prunableLeaves = new HashSet<ReferenceReportNode>();
+
+ CharArrayWriter charArray = new CharArrayWriter();
+ PrintWriter out = new PrintWriter(charArray);
+
+ try
+ {
+ exploreObject(root, thatObject, 0, maxLevel, useToString, false, referencesMap, new HashSet(), prunableLeaves);
+
+ if (condensed)
+ {
+ for (Iterator<ReferenceReportNode> it = prunableLeaves.iterator(); it.hasNext();)
+ {
+ it.next().removeBranch();
+ }
+ }
+
+ writeReport(root, out);
+ }
+ catch (Exception e)
+ {
+ charArray = new CharArrayWriter();
+ out = new PrintWriter(charArray);
+ e.printStackTrace(out);
+ }
+
+ return charArray.toString();
+ }
+
+ /** Explore references recursively */
+ private void exploreObject(ReferenceReportNode node, Object source, int currentLevel, final int maxLevel,
+ boolean useToString, boolean weakAndSoft, Map mapDataPoints, Set alreadyExplored, Set prunableLeaves)
+ {
+ String level = null;
+ {
+ StringBuffer levelStr = new StringBuffer();
+ for (int i = 0; i <= currentLevel; i++)
+ {
+ levelStr.append("!--");
+ }
+ level = levelStr.toString();
+ }
+
+ if (maxLevel >= 0 && currentLevel >= maxLevel)
+ {
+ ReferenceReportNode child = new ReferenceReportNode(level + "<b>MaxLevel</b>)");
+ node.addChild(child);
+ return;
+ }
+
+ Integer index = new Integer(System.identityHashCode(source));
+
+ if (alreadyExplored.contains(index))
+ {
+ String message = null;
+ if (source instanceof Class)
+ {
+ message = level + " object instanceOf " + source + "@" + index
+ + " was already described before on this report";
+ }
+ else
+ {
+ message = level + " object instanceOf " + source.getClass() + "@" + index
+ + " was already described before on this report";
+ }
+
+ ReferenceReportNode child = new ReferenceReportNode(message);
+ node.addChild(child);
+ prunableLeaves.add(child);
+ return;
+ }
+
+ alreadyExplored.add(index);
+
+ log.info("resolving references of " + callToString(source, useToString) + "...");
+ Long sourceTag = new Long(this.getTagOnObject(source));
+ ArrayList listPoints = (ArrayList) mapDataPoints.get(sourceTag);
+ if (listPoints == null)
+ {
+ log.info("didn't find references");
+ return;
+ }
+
+ log.info("References found");
+
+ Iterator iter = listPoints.iterator();
+
+ while (iter.hasNext())
+ {
+ ReferenceDataPoint point = (ReferenceDataPoint) iter.next();
+
+ ReferenceReportNode child = new ReferenceReportNode();
+
+ Object nextReference = treatReference(level, node, point, useToString);
+
+ if (nextReference != null && !weakAndSoft)
+ {
+ if (nextReference instanceof WeakReference || nextReference instanceof SoftReference)
+ {
+ nextReference = null;
+ prunableLeaves.add(child);
+ }
+ }
+
+ if (nextReference != null)
+ {
+ exploreObject(child, nextReference, currentLevel + 1, maxLevel, useToString, weakAndSoft, mapDataPoints,
+ alreadyExplored, prunableLeaves);
+ }
+ }
+
+ }
+
+ private void writeReport(ReferenceReportNode node, PrintWriter out)
+ {
+ out.println("<br>");
+ out.print(node.getMessage());
+
+ for (Iterator<ReferenceReportNode> it = node.getChildren().iterator(); it.hasNext();)
+ {
+ writeReport(it.next(), out);
+ }
+ }
+
+ private String callToString(Object obj, boolean callToString)
+ {
+
+ try
+ {
+ if (obj == null)
+ {
+ return "null";
+ }
+ else
+ {
+ if (callToString)
+ {
+ return obj.toString();
+ }
+ else
+ {
+ if (obj instanceof Class)
+ {
+ return obj.toString();
+ }
+ else
+ {
+ return obj.getClass().getName() + "@" + System.identityHashCode(obj);
+ }
+ }
+ }
+
+ }
+ catch (Throwable e)
+ {
+ return obj.getClass().getName() + " toString had an Exception ";
+ }
+ }
+
+ private Object treatReference(String level, ReferenceReportNode node, ReferenceDataPoint point, boolean useToString)
+ {
+ Object referenceHolder = null;
+ if (point.getReferenceHolder() == 0 || point.getReferenceHolder() == -1)
+ {
+ referenceHolder = null;
+ }
+ else
+ {
+ referenceHolder = this.getObjectOnTag(point.getReferenceHolder());
+ }
+
+ Object nextReference = null;
+ CharArrayWriter charArray = new CharArrayWriter();
+ PrintWriter out = new PrintWriter(charArray);
+
+ switch (point.getReferenceType())
+ {
+ case JVMTICallBack.JVMTI_REFERENCE_CLASS :
+ // Reference from an object to its class.
+ out.print(level + "InstanceOfReference:");
+ out.println("ToString=" + callToString(referenceHolder, useToString));
+
+ nextReference = referenceHolder;
+ break;
+ case JVMTICallBack.JVMTI_REFERENCE_FIELD :
+ // Reference from an objectb to the value of one of its
+ // instance fields. For references of this kind
+ // the referrer_index parameter to the
+ // jvmtiObjectReferenceCallback is the index of the the
+ // instance field. The index is based on the order of
+ // all the object's fields. This includes all fields
+ // of the directly declared static and instance fields
+ // in the class, and includes all fields (both public
+ // and private) fields declared in superclasses
+ // and superinterfaces. The index is thus calculated
+ // by summing the index of field in the directly
+ // declared class (see GetClassFields), with the
+ // total number of fields (both public and private)
+ // declared in all superclasses and superinterfaces.
+ // The index starts at zero.
+ {
+
+ String fieldName = null;
+
+ if (referenceHolder == null)
+ {
+ fieldName = "Reference GONE";
+ }
+ else
+ {
+ Class clazz = referenceHolder.getClass();
+ Field field = this.getObjectField(clazz, (int) point.getIndex());
+ if (field == null)
+ {
+ fieldName = "UndefinedField@" + referenceHolder;
+ }
+ else
+ {
+ fieldName = field.toString();
+ }
+ }
+ out.print(level + " FieldReference " + fieldName + "=" + callToString(referenceHolder, useToString));
+ nextReference = referenceHolder;
+ break;
+ }
+ case JVMTICallBack.JVMTI_REFERENCE_ARRAY_ELEMENT :
+ // Reference from an array to one of its elements. For
+ // references of this kind the referrer_index parameter to the
+ // jvmtiObjectReferenceCallback is the array index.
+
+ if (referenceHolder == null)
+ {
+ out.println(level + " arrayRef Position " + point.getIndex() + " is gone");
+ }
+ else
+ {
+ out.println(level + " arrayRef " + referenceHolder.getClass().getName() + "[" + point.getIndex()
+ + "] id=@" + System.identityHashCode(referenceHolder));
+ }
+ nextReference = referenceHolder;
+ break;
+ case JVMTICallBack.JVMTI_REFERENCE_CLASS_LOADER :
+ // Reference from a class to its class loader.
+
+ out.println(level + "ClassLoaderReference @ " + callToString(referenceHolder, useToString));
+ nextReference = referenceHolder;
+ break;
+ case JVMTICallBack.JVMTI_REFERENCE_SIGNERS :
+ // Reference from a class to its signers array.
+ out.println(level + "ReferenceSigner@" + callToString(referenceHolder, useToString));
+ nextReference = referenceHolder;
+ break;
+ case JVMTICallBack.JVMTI_REFERENCE_PROTECTION_DOMAIN :
+ // Reference from a class to its protection domain.
+ out.println(level + "ProtectionDomain@" + callToString(referenceHolder, useToString));
+ nextReference = referenceHolder;
+ break;
+ case JVMTICallBack.JVMTI_REFERENCE_INTERFACE :
+ // Reference from a class to one of its interfaces.
+ out.println(level + "ReferenceInterface@" + callToString(referenceHolder, useToString));
+ nextReference = referenceHolder;
+ break;
+ case JVMTICallBack.JVMTI_REFERENCE_STATIC_FIELD :// Reference from a
+ // class to the
+ // value of one of
+ // its static
+ // fields. For
+ // references of
+ // this kind the
+ // referrer_index
+ // parameter to the
+ // jvmtiObjectReferenceCallback
+ // is the index of
+ // the static field.
+ // The index is
+ // based on the
+ // order of the
+ // directly declared
+ // static and
+ // instance fields
+ // in the class (not
+ // inherited
+ // fields), starting
+ // at zero. See
+ // GetClassFields.
+ {
+ Class clazz = (Class) referenceHolder;
+ Field field = this.getObjectField(clazz, (int) point.getIndex());
+ String fieldName = null;
+ if (field == null)
+ {
+ fieldName = "UndefinedField@" + referenceHolder;
+ }
+ else
+ {
+ fieldName = field.toString();
+ }
+ out.println(level + " StaticFieldReference " + fieldName);
+ nextReference = null;
+ break;
+ }
+ case JVMTICallBack.JVMTI_REFERENCE_CONSTANT_POOL :// Reference from a
+ // class to a
+ // resolved entry in
+ // the constant
+ // pool. For
+ // references of
+ // this kind the
+ // referrer_index
+ // parameter to the
+ // jvmtiObjectReferenceCallback
+ // is the index into
+ // constant pool
+ // table of the
+ // class, starting
+ // at 1. See The
+ // Constant Pool in
+ // the Java Virtual
+ // Machine
+ // Specification.
+ out.println(level + "ReferenceInterface@" + callToString(referenceHolder, useToString));
+ nextReference = referenceHolder;
+ break;
+ case JVMTICallBack.ROOT_REFERENCE :
+ out.println(level + "Root");
+ nextReference = null;
+ break;
+ case JVMTICallBack.THREAD_REFERENCE :
+ ;
+
+ Class methodClass = this.getMethodClass(point.getMethod());
+ if (methodClass != null)
+ {
+ String className = null;
+ if (methodClass != null)
+ {
+ className = methodClass.getName();
+ }
+
+ Thread.yield();
+
+ // this is weird but without this sleep here, the JVM crashes.
+ /*
+ * try { Thread.sleep(10); } catch (InterruptedException e) {
+ * e.printStackTrace(); }
+ */
+
+ String methodName = this.getMethodName(point.getMethod());
+ out.println(level + " Reference inside a method - " + className + "::" + methodName);
+ }
+ nextReference = null;
+ break;
+ default :
+ log.warn("unexpected reference " + point);
+ }
+
+ node.setMessage(charArray.toString());
+
+ return nextReference;
+ }
+}
Added: trunk/testsuite/src/main/org/jboss/test/classloader/leak/clstore/ReferenceReportNode.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/classloader/leak/clstore/ReferenceReportNode.java (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/classloader/leak/clstore/ReferenceReportNode.java 2007-03-11 05:38:02 UTC (rev 61262)
@@ -0,0 +1,93 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.test.classloader.leak.clstore;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A node (i.e. line item) in a {@link LeakAnalyzer} report.
+ *
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1.1 $
+ */
+public class ReferenceReportNode
+{
+ private String message;
+ private List<ReferenceReportNode> children = new ArrayList<ReferenceReportNode>();;
+ private ReferenceReportNode parent;
+
+ public ReferenceReportNode()
+ {
+ }
+
+ public ReferenceReportNode(String msg)
+ {
+ this.message = msg;
+ }
+
+ public void addChild(ReferenceReportNode child)
+ {
+ children.add(child);
+ child.setParent(this);
+ }
+
+ public void removeBranch()
+ {
+ if (parent != null)
+ parent.removeChild(this);
+ }
+
+ private void removeChild(ReferenceReportNode child)
+ {
+ children.remove(child);
+ if (children.size() == 0)
+ removeBranch();
+ }
+
+ public List<ReferenceReportNode> getChildren()
+ {
+ return Collections.unmodifiableList(children);
+ }
+
+ public ReferenceReportNode getParent()
+ {
+ return parent;
+ }
+
+ private void setParent(ReferenceReportNode parent)
+ {
+ this.parent = parent;
+ }
+
+ public String getMessage()
+ {
+ return message;
+ }
+
+ public void setMessage(String msg)
+ {
+ this.message = msg;
+ }
+}
\ No newline at end of file
More information about the jboss-cvs-commits
mailing list