[jboss-cvs] JBossAS SVN: r61271 - branches/Branch_4_2/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 20:28:11 EDT 2007
Author: bstansberry at jboss.com
Date: 2007-03-11 20:28:11 -0400 (Sun, 11 Mar 2007)
New Revision: 61271
Added:
branches/Branch_4_2/testsuite/src/main/org/jboss/test/classloader/leak/clstore/LeakAnalyzer.java
branches/Branch_4_2/testsuite/src/main/org/jboss/test/classloader/leak/clstore/ReferenceReportNode.java
Log:
Support for condensed format classloader leak reports
Copied: branches/Branch_4_2/testsuite/src/main/org/jboss/test/classloader/leak/clstore/LeakAnalyzer.java (from rev 61262, trunk/testsuite/src/main/org/jboss/test/classloader/leak/clstore/LeakAnalyzer.java)
===================================================================
--- branches/Branch_4_2/testsuite/src/main/org/jboss/test/classloader/leak/clstore/LeakAnalyzer.java (rev 0)
+++ branches/Branch_4_2/testsuite/src/main/org/jboss/test/classloader/leak/clstore/LeakAnalyzer.java 2007-03-12 00:28:11 UTC (rev 61271)
@@ -0,0 +1,449 @@
+/*
+ * 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 java.util.WeakHashMap;
+
+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
+{
+ WeakHashMap whm;
+ 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);
+
+ for (Iterator<ReferenceReportNode> it = prunableLeaves.iterator(); it.hasNext();)
+ {
+ ReferenceReportNode nonCrit = it.next();
+ nonCrit.markNonCritical();
+ if (condensed)
+ nonCrit.removeBranch();
+ }
+
+ writeReport(root, 0, 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)
+ {
+ if (maxLevel >= 0 && currentLevel >= maxLevel)
+ {
+ node.setMessage("<i>MaxLevel</i>)");
+ return;
+ }
+
+ Integer index = new Integer(System.identityHashCode(source));
+
+ if (alreadyExplored.contains(index))
+ {
+ String message = null;
+ if (source instanceof Class)
+ {
+ message = " object instanceOf " + source + "@" + index
+ + " was already described before on this report";
+ }
+ else
+ {
+ message = " object instanceOf " + source.getClass() + "@" + index
+ + " was already described before on this report";
+ }
+
+ node.setMessage(message);
+ prunableLeaves.add(node);
+ 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");
+
+ for (Iterator iter = listPoints.iterator(); iter.hasNext();)
+ {
+ ReferenceDataPoint point = (ReferenceDataPoint) iter.next();
+
+ ReferenceReportNode child = new ReferenceReportNode();
+
+ Object nextReference = treatReference(child, point, useToString);
+
+ if (nextReference != null && !weakAndSoft)
+ {
+ if (nextReference instanceof WeakReference || nextReference instanceof SoftReference)
+ {
+ // WeakHashMap$Entry and ThreadLocal$ThreadLocalMap$Entry are
+ // special cases, where the Entry key is a weak ref, but the
+ // value is strong. We don't want to ignore similar cases. So
+ // only mark as prunable if the ref is the standard
+ // java.lang.ref.Referent.referent -- all others are potential
+ // strong references
+ String msg = child.getMessage();
+ if (msg.indexOf("java.lang.ref.Reference.referent=") >= 0)
+ {
+ prunableLeaves.add(child);
+ }
+
+ nextReference = null;
+ }
+ }
+
+ if (nextReference != null)
+ {
+ exploreObject(child, nextReference, currentLevel + 1, maxLevel, useToString, weakAndSoft, mapDataPoints,
+ alreadyExplored, prunableLeaves);
+ }
+
+ if (child.getMessage() != null || child.getChildren().size() > 0)
+ node.addChild(child);
+
+ }
+
+ }
+
+ private void writeReport(ReferenceReportNode node, int level, PrintWriter out)
+ {
+ out.print("<br>");
+ out.print(writeLevel(level));
+ if (node.isCritical())
+ {
+ out.print("<b>");
+ if (node.isLeaf())
+ {
+ out.print("<font color=\"red\">");
+ }
+ out.print(node.getMessage());
+ if (node.isLeaf())
+ {
+ out.print("</font>");
+ }
+ out.println("</b>");
+ }
+ else
+ {
+ out.println(node.getMessage());
+ }
+
+ for (Iterator<ReferenceReportNode> it = node.getChildren().iterator(); it.hasNext();)
+ {
+ writeReport(it.next(), level + 1, 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(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("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("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("arrayRef Position " + point.getIndex() + " is gone");
+ }
+ else
+ {
+ out.println("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("ClassLoaderReference @ " + callToString(referenceHolder, useToString));
+ nextReference = referenceHolder;
+ break;
+ case JVMTICallBack.JVMTI_REFERENCE_SIGNERS :
+ // Reference from a class to its signers array.
+ out.println("ReferenceSigner@" + callToString(referenceHolder, useToString));
+ nextReference = referenceHolder;
+ break;
+ case JVMTICallBack.JVMTI_REFERENCE_PROTECTION_DOMAIN :
+ // Reference from a class to its protection domain.
+ out.println("ProtectionDomain@" + callToString(referenceHolder, useToString));
+ nextReference = referenceHolder;
+ break;
+ case JVMTICallBack.JVMTI_REFERENCE_INTERFACE :
+ // Reference from a class to one of its interfaces.
+ out.println("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("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(" ReferenceInterface@" + callToString(referenceHolder, useToString));
+ nextReference = referenceHolder;
+ break;
+ case JVMTICallBack.ROOT_REFERENCE :
+ out.println("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("Reference inside a method - " + className + "::" + methodName);
+ }
+ nextReference = null;
+ break;
+ default :
+ log.warn("unexpected reference " + point);
+ }
+
+ String msg = charArray.toString();
+ if (msg.trim().length() > 0)
+ node.setMessage(msg);
+
+ return nextReference;
+ }
+
+ private static String writeLevel(int level)
+ {
+ StringBuffer levelSb = new StringBuffer();
+ for (int i = 0; i <= level; i++)
+ {
+ levelSb.append("!--");
+ }
+ return levelSb.toString();
+ }
+}
Copied: branches/Branch_4_2/testsuite/src/main/org/jboss/test/classloader/leak/clstore/ReferenceReportNode.java (from rev 61262, trunk/testsuite/src/main/org/jboss/test/classloader/leak/clstore/ReferenceReportNode.java)
===================================================================
--- branches/Branch_4_2/testsuite/src/main/org/jboss/test/classloader/leak/clstore/ReferenceReportNode.java (rev 0)
+++ branches/Branch_4_2/testsuite/src/main/org/jboss/test/classloader/leak/clstore/ReferenceReportNode.java 2007-03-12 00:28:11 UTC (rev 61271)
@@ -0,0 +1,124 @@
+/*
+ * 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;
+ private Boolean critical = Boolean.TRUE;
+ private int nonCriticalChildren = 0;
+
+ public ReferenceReportNode()
+ {
+ }
+
+ public ReferenceReportNode(String msg)
+ {
+ this.message = msg;
+ }
+
+ public void addChild(ReferenceReportNode child)
+ {
+ children.add(child);
+ child.setParent(this);
+ critical = null;
+ }
+
+ public void removeBranch()
+ {
+ if (parent != null)
+ parent.removeChild(this);
+ }
+
+ private void removeChild(ReferenceReportNode child)
+ {
+ children.remove(child);
+ if (children.size() == 0)
+ removeBranch();
+ }
+
+ public boolean isLeaf()
+ {
+ return children.size() == 0;
+ }
+
+ public boolean isCritical()
+ {
+ if (critical != null)
+ {
+ return critical.booleanValue();
+ }
+ return (children.size() - nonCriticalChildren > 0);
+ }
+
+ public void markNonCritical()
+ {
+ critical = Boolean.FALSE;
+ if (parent != null)
+ parent.markChildNonCritical();
+ }
+
+ private void markChildNonCritical()
+ {
+ nonCriticalChildren++;
+ if (!isCritical() && parent != null)
+ parent.markChildNonCritical();
+ }
+
+ 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