[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