Package org.apache.kato.hprof

Source Code of org.apache.kato.hprof.HProfView$JavaClassLoader

/*******************************************************************************
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.apache.kato.hprof;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Vector;

import org.apache.kato.common.BasicType;
import org.apache.kato.common.ClassSummary;
import org.apache.kato.common.IDLocationMap;
import org.apache.kato.common.IDToLocationHashMapper;
import org.apache.kato.common.IViewMonitor;
import org.apache.kato.hprof.datalayer.ConstantPoolEntry;
import org.apache.kato.hprof.datalayer.HProfFile;
import org.apache.kato.hprof.datalayer.IGCClassHeapDumpRecord;
import org.apache.kato.hprof.datalayer.IHProfRecord;
import org.apache.kato.hprof.datalayer.IHeapDumpHProfRecord;
import org.apache.kato.hprof.datalayer.IHeapObject;
import org.apache.kato.hprof.datalayer.IJavaStackFrameHProfRecord;
import org.apache.kato.hprof.datalayer.IJavaStackTraceHProfRecord;
import org.apache.kato.hprof.datalayer.ILoadClassHProfRecord;
import org.apache.kato.hprof.datalayer.IThreadActiveHProfRecord;
import org.apache.kato.hprof.datalayer.IThreadEndingHProfRecord;
import org.apache.kato.hprof.datalayer.IUTF8HProfRecord;
import org.apache.kato.hprof.datalayer.IUnloadClassHProfRecord;
import org.apache.kato.hprof.datalayer.InstanceFieldEntry;
import org.apache.kato.hprof.datalayer.StaticFieldEntry;

public class HProfView {

  private HProfFile file = null;
  private HashMap<Long, Integer> utf8s = new HashMap<Long, Integer>();
  private Long[] utf8ids = null;
  private IJavaClass[] loadedClassRecordNumbers = null;
  private IJavaThread[] threads = null;
  private HashMap<Integer, Integer> stackTraces = new HashMap<Integer, Integer>();
  private Integer[] stackTraceRecords=null;
  private HashMap<Long, Integer> stackTraceFrames = new HashMap<Long, Integer>();
  private ClassSummary recordSummary=null;
  private IHeapDumpHProfRecord heapRecord=null;
  private long heapRecordLocation=0;
//  private HashMap<Long,JavaClassLoader> = new HashMap<Long,JavaClassLoader>();
  private IDLocationMap idToLocationMap;
 
  // Class maps
  private HashMap<Long,IJavaClassLoader> javaClassLoaders = new HashMap<Long,IJavaClassLoader>();
  private HashMap<Integer,IJavaClass>  loadedClassesBySerial=new HashMap<Integer,IJavaClass>();
  private HashMap<Long,IJavaClass>  loadedClassesByID=new HashMap<Long,IJavaClass>();
 
  // Thread ID Maps
  private HashMap<Integer,IJavaThread> activeThreadsBySerial = new HashMap<Integer, IJavaThread>();

  /**
   * Takes an open file.
   *
   * @param file
   */
  public HProfView(HProfFile file) {
    this.file = file;
  }

  public void open(IViewMonitor monitor) {

  //  try {
  //  file.open();
  //  } catch(IOException ioe) {
  //    throw new IllegalArgumentException(ioe);
  //  }
    int r = 0;
    LinkedList<IJavaClass> loadedClassesRecordNO = new LinkedList<IJavaClass>();
    LinkedList<IJavaThread> threadRecordNO = new LinkedList<IJavaThread>();
    LinkedList<Integer> javastacks = new LinkedList<Integer>();
    idToLocationMap = new IDToLocationHashMapper();

    recordSummary=new ClassSummary();

    int heapRecordNo=0;
    while (true) {
      IHProfRecord record = file.getRecord(r);
      if (record == null)
        break;

      String tagName=HProfRecordFormatter.getTagName(record);
      recordSummary.record(record);
      if (record instanceof IUTF8HProfRecord) {
        IUTF8HProfRecord utf8 = (IUTF8HProfRecord) record;
        Long id = utf8.getNameID();
        utf8s.put(id, r);

      } else if (record instanceof ILoadClassHProfRecord) {
        JavaClass c=new JavaClass(r);         
        loadedClassesBySerial.put(c.getClassSerialNumber(),c);
      } else if (record instanceof IUnloadClassHProfRecord) {         
        // Remove a loaded class if it is subsequently unloaded.
        loadedClassesBySerial.remove(((IUnloadClassHProfRecord)record).getClassSerialNumber());
      } else if (record instanceof IThreadActiveHProfRecord) {
        ActiveJavaThread ajt = new ActiveJavaThread(r);

        threadRecordNO.add( ajt );

        // add by serial number
        activeThreadsBySerial.put(ajt.getThreadSerialNumber(), ajt);
      } else if (record instanceof IThreadEndingHProfRecord) {
        InactiveJavaThread ijt = new InactiveJavaThread(r);

        threadRecordNO.add(ijt);
        // remove thread by serial number.
        //SRDM activeThreadsBySerial.remove(ijt.getThreadSerialNumber());
      } else if (record instanceof IJavaStackTraceHProfRecord) {
        // Stack traces should be attached to threads
        // keep the most recent. Attach to thread so that when thread removed,
        // stacktrace is removed too.
        IJavaStackTraceHProfRecord stackTrace = (IJavaStackTraceHProfRecord) record;
        int sn = stackTrace.getSerialNumber();

        stackTraces.put(sn, r);
        javastacks.add(r);

        // Attach this stack trace to its thread if the thread
        // exists and this trace is newer.
        int threadSerial = stackTrace.getThreadSerialNumber();       
        IJavaThread ajt = activeThreadsBySerial.get(threadSerial);

        if(ajt != null) {
          ((ActiveJavaThread)ajt).setStackTrace(stackTrace);
        }

      } else if (record instanceof IJavaStackFrameHProfRecord) {
        IJavaStackFrameHProfRecord frame = (IJavaStackFrameHProfRecord) record;
        long id = frame.getStackFrameID();
        stackTraceFrames.put(id, r);

      }
      else if(record instanceof IHeapDumpHProfRecord) {
        heapRecord=(IHeapDumpHProfRecord) record;
        heapRecordNo=r;

        summariseHeap(heapRecord);
      }
      r++;
    }

    heapRecordLocation=file.getRecordLocation(heapRecordNo);

    utf8ids = utf8s.keySet().toArray(new Long[0]);
    loadedClassRecordNumbers = loadedClassesRecordNO
    .toArray(new IJavaClass[0]);

    threads = threadRecordNO.toArray(new IJavaThread[0]);
    stackTraceRecords=javastacks.toArray(new Integer[0]);     

    correlateClasses();
  }

  private IJavaClass[] primitiveArrayClasses = new IJavaClass[8];
  /**
   * Called once during processing.
   * Iterates over all of the classes loaded and never unloaded.
   * Creates the JavaClassLoaders, and creates map from object IDs to JavaClasses.
   *
   */
  private void correlateClasses() {

    Iterator<Integer> classes = loadedClassesBySerial.keySet().iterator();
 
    while (classes.hasNext()) {
      int classSerialNo = classes.next();
      IJavaClass clazz = loadedClassesBySerial.get(classSerialNo);
     
      Long location =  idToLocationMap.getLocation(clazz.getClassObjectID());
     
      if (location == null) {
        continue;
      }
     
      IHProfRecord record =  heapRecord.getSubRecordByLocation(location);
      long classLoaderObjectID = 0L;
      long classObjectID = 0L;
      if (record instanceof IGCClassHeapDumpRecord) {
        IGCClassHeapDumpRecord classRecord = (IGCClassHeapDumpRecord) record;
       
        classLoaderObjectID = classRecord.getClassLoaderObjectID();
       
        classObjectID = classRecord.getID();
       
        String name = clazz.getClassName();
       
        if ("boolean[]".equals(name)) {
          primitiveArrayClasses[BasicType.BOOLEAN-4] = clazz;
        } else if ("byte[]".equals(name)) {
          primitiveArrayClasses[BasicType.BYTE-4] = clazz;
        } else if ("char[]".equals(name)) {
          primitiveArrayClasses[BasicType.CHAR-4] = clazz;
        } else if ("short[]".equals(name)) {
          primitiveArrayClasses[BasicType.SHORT-4] = clazz;
        } else if ("int[]".equals(name)) {
          primitiveArrayClasses[BasicType.INT-4] = clazz;
        } else if ("long[]".equals(name)) {
          primitiveArrayClasses[BasicType.LONG-4] = clazz;
        } else if ("float[]".equals(name)) {
          primitiveArrayClasses[BasicType.FLOAT-4] = clazz;
        } else if ("double[]".equals(name)) {
          primitiveArrayClasses[BasicType.DOUBLE-4] = clazz;
        }
       
        // Create map of classes loaded by ID.
        loadedClassesByID.put(classObjectID, clazz);
      } else {
        // If the record wasn't pointing to a class, then don't do anything with this class.
        continue;
      }
     
      // retrieve classloader by ID. If it doesn't match, create one.
      // then add this class object ID.
      JavaClassLoader loader = (JavaClassLoader) javaClassLoaders.get(classLoaderObjectID);
     
      if (loader == null) {
        loader = new JavaClassLoader(classLoaderObjectID);
        javaClassLoaders.put(classLoaderObjectID, loader);
      }
     
      loader.addClass(classObjectID);
    }
   
  }
 
  /**
   * Primitive
   * @param type
   * @return
   */
  public IJavaClass getPrimitiveArrayClass(int type) {
     if(type <4 || type >11) {
       throw new IllegalArgumentException("Invalid basic type for primitive array " + type);
     }
    
     return primitiveArrayClasses[type-4];
  }
 
  /**
   * Returns a collection of all of the JavaClassLoaders.
   *
   * @return Collection<JavaClassLoader>
   */
  public Collection<IJavaClassLoader> getJavaClassLoaders() {
    return javaClassLoaders.values();
  }
 
  /**
   * Given the Object ID of a JavaClassLoader, return a JavaClassLoader
   * of it's ID.
   *
   * @param id
   * @return
   */
  public IJavaClassLoader getJavaClassLoader(long id) {
    return javaClassLoaders.get(id);
  }

  /**
   * Return a JavaClass by its serial number.
   *
   * @param serial
   * @return IJavaClass instance or null.
   */
  public IJavaClass getJavaClassBySerial(int serial) {
    return loadedClassesBySerial.get(serial);
  }
 
  /**
   * Return a IJavaClass instance referenced by its ID.
   * @param id object ID of class
   * @return IJavaClass or null
   */
  public IJavaClass getJavaClassByID(long id) {   
    IJavaClass clazz = loadedClassesByID.get(id);
   
    if (clazz == null) {
      System.err.println("Failed class lookup : 0x" +
          Long.toHexString(id));
    }
    //assert(clazz != null);
   
    return clazz;
  }
 
  /**
   * Return an IHeapObject instance with the passed object ID.
   *
   * @param id
   * @return IJavaObject with passed ID
   */
  public IHeapObject getJavaObjectByID(long id) {
    Long loc = idToLocationMap.getLocation(id);
    if (loc == null) {
      return null;
    }
   
    IHProfRecord record =  heapRecord.getSubRecordByLocation(loc);
   
    if (record == null) {
      return null;
    }
   
    if (record instanceof IHeapObject) {
      return (IHeapObject) record;
    }
   
    return null;
  }
 
  private void summariseHeap(IHeapDumpHProfRecord heapRecord) {
   
    int index=0;
   
    while(true) {
      IHProfRecord rec=heapRecord.getSubRecord(index);
     
      /* Record the ID of this record and location in ID to record map
       * if this record is of an appropriate type.
       */
      if (rec instanceof IHeapObject) {
        long location = heapRecord.getSubRecordLocation(index);
        idToLocationMap.put(((IHeapObject)rec).getID(), location);
      }
           
      if(rec==null) break;
      recordSummary.record(rec);
      index++;
    }
   
  }

  public IJavaStackFrameHProfRecord getStackFrameRecordFromID(long id) {
    int record=stackTraceFrames.get(id);
    return (IJavaStackFrameHProfRecord) file.getRecord(record);
  }
  public String getName(long id) {
    return getUTF8String(id);

  }

  public String getUTF8String(long id) {

    int record = getUTF8RecordID(id);
    if (record < 0)
      return "";
    IHProfRecord rec = file.getRecord(record);
    if (rec == null)
      return null;
    if (rec instanceof IUTF8HProfRecord) {
      IUTF8HProfRecord utf8record = (IUTF8HProfRecord) rec;
      return utf8record.getAsString();
    }

    return null;
  }

  public int getUTF8RecordID(long id) {
    if (utf8s.containsKey(id)) {
      int record = utf8s.get(id);
      return record;
    }
    return -1;
  }

  public int getThreadCount() {
    return threads.length;
  }

  public IJavaThread getThread(int ref) {
    return threads[ref];
  }

  public int getStackTraceCount() {
    return stackTraceRecords.length;
  }
  public IJavaStackTraceHProfRecord getStackTraceRecord(int ref) {
    return (IJavaStackTraceHProfRecord) file.getRecord(stackTraceRecords[ref]);
  }

  /**
   * Represents a JavaClass - pulls together the LoadClass hprofrecord
   * and it corresponding GCClassHeapDumpRecord.
   *
   */
  public class JavaClass implements IJavaClass {

    private int ref = 0;

    private JavaClass(int r) {
      this.ref = r;
    }

    @Override
    public String getClassName() {
      ILoadClassHProfRecord record = getLoadedClassHProfRecord(ref);
      return getName(record.getClassNameID());
    }

    @Override
    public long getClassObjectID() {
      return getLoadedClassHProfRecord(ref).getClassObjectID();

    }

    @Override
    public int getClassSerialNumber() {

      return getLoadedClassHProfRecord(ref).getClassSerialNumber();
    }

    @Override
    public int getStackTraceSerialNumber() {

      return getLoadedClassHProfRecord(ref).getStackTraceSerialNumber();
    }

    @Override
    public long getClassLoaderObjectID() {
      return getHProfRecord().getClassLoaderObjectID();
    }
   
   
    private IGCClassHeapDumpRecord getHProfRecord() {
      return (IGCClassHeapDumpRecord) heapRecord.getSubRecordByLocation(idToLocationMap.getLocation(getClassObjectID()));
    }

    @Override
    public long getSuperClassObjectID() {
      return getHProfRecord().getSuperClassObjectID();
    }
   
    @Override
    public int getInstanceSize() {
      return getHProfRecord().getInstanceSize();
    }
   

    /**
     * Check for equality
     */
    @Override
    public boolean equals(Object obj) {
      if (obj == null) {
        return false;
      } else if (!(obj instanceof JavaClass)) {
        return false;
      }
      return ((JavaClass)obj).getClassSerialNumber() == getClassSerialNumber();
    }

    @Override
    public long getProtectionDomainObjectID() {
      return getHProfRecord().getProtectionDomainObjectID();
    }

    @Override
    public long getSignersObjectID() {
      return getHProfRecord().getSignersObjectID();
    }

    @Override
    public StaticFieldEntry[] getStaticFields() {
      return getHProfRecord().getStaticFields();
    }

    @Override
    public ConstantPoolEntry[] getConstantPoolEntries() {
      return getHProfRecord().getConstantPool();
    }

    @Override
    public InstanceFieldEntry[] getInstanceFields() {
      return getHProfRecord().getInstanceFields();
    }

    @Override
    public int getOffsetSize() {
      return getHProfRecord().getOffsetSize();
    }
  }

  /**
   * Holds the IDs of classes loaded by this classloader.
   *
   */
  private class JavaClassLoader implements IJavaClassLoader {
    private Long id;
    private Vector<Long> classes = new Vector<Long>();
   
    /**
     * Creates a JavaClassLoader.
     * This identifying object ID is passed.
     *
     * @param id Object ID of the class loader.
     */
    private JavaClassLoader(Long id) {
      this.id = id;
    }
   
    /**
     * Returns the Object ID of this classloader.
     * @return long
     */
    public long getID() {
      return this.id;
    }
   
    /**
     * Add a class to the classloader.
     * Private as only the
     * @param ID
     */
    private void addClass(Long ID) {
      this.classes.add(ID);
    }
   
    public Vector<Long> getClasses() {
      return classes;
    }
  }
   
  public class InactiveJavaThread implements IJavaThread {
    private int ref = 0;

    private InactiveJavaThread(int ref) {
      this.ref = ref;

    }

    @Override
    public int getStackTraceSerialNumber() {

      return 0;

    }

    @Override
    public String getThreadGroupName() {

      return "";
    }

    @Override
    public String getThreadGroupParentName() {
      return "";
    }

    @Override
    public String getThreadName() {
      return "";
    }

    @Override
    public long getThreadObjectID() {

      return 0;
    }

    @Override
    public int getThreadSerialNumber() {

      return getEndingJavaThreadRecord(ref).getThreadSerialNumber();
    }

    @Override
    public boolean isActive() {

      return false;
    }

    @Override
    public IJavaStack getStack() {
     
      return null;
    }
  }

  public class ActiveJavaThread implements IJavaThread {

    private final class JavaStackFrame implements IJavaStackFrame {
      private int frameRecord=0;
      public JavaStackFrame(int stackRecord) {
        this.frameRecord=stackRecord;
      }

      @Override
      public Long getID() {
        IJavaStackFrameHProfRecord record=(IJavaStackFrameHProfRecord) file.getRecord(frameRecord);
        return record.getStackFrameID();
      }

      @Override
      public int getLineNumber() {
        IJavaStackFrameHProfRecord record=(IJavaStackFrameHProfRecord) file.getRecord(frameRecord);
        return record.getLineNumber();
      }

      @Override
      public IJavaClass getMethodClass() {
        IJavaStackFrameHProfRecord record=(IJavaStackFrameHProfRecord) file.getRecord(frameRecord);
        int sn=record.getClassSerialNumber();
        return loadedClassesBySerial.get(sn);
      }

      @Override
      public String getMethodName() {
        IJavaStackFrameHProfRecord record=(IJavaStackFrameHProfRecord) file.getRecord(frameRecord);
        long id=record.getMethodNameID();
        return getName(id);
      }

      @Override
      public String getMethodSignature() {
        IJavaStackFrameHProfRecord record=(IJavaStackFrameHProfRecord) file.getRecord(frameRecord);
        long id=record.getMethodSignatureID();
        return getName(id);
      }

      @Override
      public String getSourceFileName() {
        IJavaStackFrameHProfRecord record=(IJavaStackFrameHProfRecord) file.getRecord(frameRecord);
        long id=record.getSourceFileNameID();
        return getName(id);
      }
    }

    private int ref = 0;

    private ActiveJavaThread(int ref) {
      this.ref = ref;

    }

    @Override
    public boolean isActive() {

      return true;
    }

    @Override
    public int getStackTraceSerialNumber() {

      return getActiveJavaThreadRecord(ref).getStackTraceSerialNumber();
    }

    @Override
    public String getThreadGroupName() {

      long id = getActiveJavaThreadRecord(ref).getThreadGroupNameID();
      return getName(id);
    }

    @Override
    public String getThreadGroupParentName() {
      long id = getActiveJavaThreadRecord(ref)
          .getThreadGroupParentNameID();
      return getName(id);
    }

    @Override
    public String getThreadName() {
      long id = getActiveJavaThreadRecord(ref).getThreadNameID();
      return getName(id);
    }

    @Override
    public long getThreadObjectID() {
      return getActiveJavaThreadRecord(ref).getThreadObjectID();
    }

    @Override
    public int getThreadSerialNumber() {
      return getActiveJavaThreadRecord(ref).getThreadSerialNumber();
    }
   
    private IJavaStackTraceHProfRecord stackTrace;
    public void setStackTrace(IJavaStackTraceHProfRecord stackTrace) {
      if (this.stackTrace == null) {
        this.stackTrace = stackTrace;
        return;
      }
     
      if (this.stackTrace.getSerialNumber() < stackTrace.getSerialNumber()) {
        this.stackTrace = stackTrace;
      }
    }
   
    @Override
    public IJavaStack getStack() {
      // stack trace record no
      IJavaStackTraceHProfRecord record = stackTrace;

      final IJavaStackFrame[] data;
      if (record != null) { // There might not be any frames with this thread.
        int stackElements = record.getFrameCount();
        data = new IJavaStackFrame[stackElements];
        for (int i = 0; i < stackElements; i++) {
          long stackFrameElementID = record.getStackFrameID(i);
          int stackRecord=stackTraceFrames.get(stackFrameElementID);
          data[i]=new JavaStackFrame(stackRecord);
        }
      } else {
        data = new IJavaStackFrame[0];
      }
     
      IJavaStack stack = new IJavaStack() {

        @Override
        public IJavaStackFrame[] getStack() {

          return data;
        }

        @Override
        public IJavaThread getThread() {
          return ActiveJavaThread.this;
        }
      };

      return stack;
    }
  }

  private IThreadEndingHProfRecord getEndingJavaThreadRecord(int ref) {

    return (IThreadEndingHProfRecord) file.getRecord(ref);
  }

  private IThreadActiveHProfRecord getActiveJavaThreadRecord(int ref) {

    return (IThreadActiveHProfRecord) file.getRecord(ref);
  }

  private ILoadClassHProfRecord getLoadedClassHProfRecord(int ref) {
    return (ILoadClassHProfRecord) file.getRecord(ref);
  }

  public int getUTF8Count() {
    return utf8ids.length;
  }

  public long getUTF8IDFromIndex(int index) {

    return utf8ids[index];
  }

  public int getLoadedClassCount() {
    return loadedClassRecordNumbers.length;
  }

  public IJavaClass getLoadedClass(int index) {
    return loadedClassRecordNumbers[index];
  }

  public HProfFile getFile() {
    return file;
  }

  public int getUTF8Length(long id) {

    int record = getUTF8RecordID(id);
    if (record < 0)
      return record;
    IHProfRecord rec = file.getRecord(record);
    if (rec == null)
      return -2;
    if (rec instanceof IUTF8HProfRecord) {
      IUTF8HProfRecord utf8record = (IUTF8HProfRecord) rec;
      return utf8record.getCharacters().length;
    }

    return -3;

  }

  public ClassSummary getRecordSummary() {
    return recordSummary;
  }

 

  public IHeapDumpHProfRecord getHeapRecord() {
   
      return heapRecord;
   
  }

  /**
   * Return the record number for the heap record
   * @return
   */
  public long getHeapRecordLocation() {
   
    return heapRecordLocation;
  }
 
  /**
   * Returns the IJavaThreads that are active, i.e.
   * haven't got corresponding END THREAD records.
   *
   * @return Collection of active JavaThreads
   */
  public Collection<IJavaThread> getActiveThreads() {
    return activeThreadsBySerial.values();
  }

  public File getSource() {
   
    return file.getSource();
  }
}
TOP

Related Classes of org.apache.kato.hprof.HProfView$JavaClassLoader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.