Package com.starlight.io.hprof

Source Code of com.starlight.io.hprof.MemoryAnalyzer

/*
* Copyright (c) 2012 Rob Eden.
* All Rights Reserved.
*/

package com.starlight.io.hprof;

import com.starlight.StringKit;
import com.starlight.types.Pair;
import gnu.trove.map.TIntLongMap;
import gnu.trove.map.TIntObjectMap;
import gnu.trove.map.TObjectIntMap;
import gnu.trove.map.TObjectLongMap;
import gnu.trove.map.hash.TIntLongHashMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.map.hash.TObjectIntHashMap;
import gnu.trove.map.hash.TObjectLongHashMap;
import gnu.trove.procedure.TIntLongProcedure;
import gnu.trove.procedure.TObjectIntProcedure;
import gnu.trove.procedure.TObjectLongProcedure;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.*;


/**
* Basic implementation of a {@link HPROFParseHandler} which analyzes an HPROF memory dump
* file.
*/
public class MemoryAnalyzer {
  public static void main( String[] args ) throws IOException {
    if ( args.length != 1 ) {
      System.out.println( "Usage: MemoryAnalyzer <hprof_file>" );
      return;
    }

    File file = new File( args[ 0 ] );

    analyze( file, System.out );
  }


  /**
   * Analyze an HPROF memory file and output the results to the given stream.
   */
  public static void analyze( File hprof_file, PrintStream output ) throws IOException {
    analyze( hprof_file, new PrintWriter( output ) );
  }

  /**
   * Analyze an HPROF memory file and output the results to the given writer.
   */
  public static void analyze( File hprof_file, PrintWriter output ) throws IOException {
    MemoryAnalyzer analyzer = new MemoryAnalyzer( output );
    HPROFParser parser = new HPROFParser( hprof_file, analyzer.handler );
    parser.parse();
  }

 
  private final PrintWriter output;
 
  private final Map<ID,String> string_map = new HashMap<ID, String>();
  private final Map<ID,ID> class_name_map = new HashMap<ID, ID>();

  private final TIntObjectMap<ID> classes = new TIntObjectHashMap<ID>();
  private final Map<ID,StackTraceElement> frames = new HashMap<ID, StackTraceElement>();
  private final TIntObjectMap<List<ID>> stack_traces = new TIntObjectHashMap<List<ID>>();

  private int instance_dumps = 0;
  private int class_dumps = 0;

  private TObjectIntMap<ID> class_instances = new TObjectIntHashMap<ID>();
  private TObjectLongMap<ID> class_aggregate_size = new TObjectLongHashMap<ID>();
  private TIntLongMap trace_counts = new TIntLongHashMap();

  private Handler handler = new Handler();


  private MemoryAnalyzer( PrintWriter output ) {
    this.output = output;
  }


  private class Handler extends AbstractHPROFParseHandler {
    @Override
    public void recordStringInUTF8( ID id, String string ) {
      string_map.put( id, string );
    }

    @Override
    public void recordLoadClass( int class_serial_number, ID object_id,
      int stack_trace_serial, ID class_name_string_id ) {

      class_name_map.put( object_id, class_name_string_id );
      classes.put( class_serial_number, object_id );
    }

    @Override
    public void recordStackFrame( ID frame_id, ID method_name_id, ID method_signature_id,
      ID source_file_name_id, int class_serial_number, int line ) {


      ID class_id = classes.get( class_serial_number );
      String class_name = "***unknown class***";
      if ( class_id != null && string_map.containsKey( class_id ) ) {
        class_name = string_map.get( class_id );
      }

      // TODO: need signature, examples:
      // Method name: init
  //              Signature: ()V
  //            Method name: <clinit>
  //              Signature: ()V
  //            Method name: socketBind
  //              Signature: (Ljava/net/ InetAddress;I)V
  //            Method name: bind
  //              Signature: (Ljava/net/InetAddress;I)V
  //            Method name: bind
  //              Signature: (Ljava/net/ SocketAddress;I)V
  //            Method name: <init>
  //              Signature: (IILjava/net/InetAddress;)V
  //            Method name: <init>
  //              Signature: (I)V
  //            Method name: run
  //              Signature: ()V


      frames.put( frame_id, new StackTraceElement( class_name,
        string_map.get( method_name_id ),
        string_map.get( source_file_name_id ), line ) );
    }


    @Override
    public void recordStackTrace( int trace_serial_number, int thread_serial_number,
      ID[] frame_ids ) {

      if ( frame_ids == null || frame_ids.length == 0 ) return;

      List<ID> frames = stack_traces.get( trace_serial_number );
      if ( frames == null ) {
        frames = new ArrayList<ID>( 2 );
        stack_traces.put( trace_serial_number, frames );
      }

      for( ID frame_id : frame_ids ) {
        frames.add( frame_id );
      }
    }


    @Override
    public void heapDumpClassDump( ID object_id, int stack_trace_serial_number,
      ID super_class_id, ID class_loader_id, ID signers_object_id,
      ID protection_domain_object_id, long instance_size, int[] constant_pool_indexes,
      BasicType[] constant_pool_types, Object[] constant_pool_values,
      ID[] static_field_names, BasicType[] static_field_types,
      Object[] static_field_values, ID[] instance_field_names,
      BasicType[] instance_field_types ) {

      class_dumps++;
    }

    @Override
    public void heapDumpInstanceDump( ID object_id, int stack_trace_serial_number,
      ID class_object_id, long data_length ) {

      instance_dumps++;
      class_instances.adjustOrPutValue( class_object_id, 1, 1 );
      class_aggregate_size.adjustOrPutValue( class_object_id, data_length, data_length );
      trace_counts.adjustOrPutValue( stack_trace_serial_number, 1, 1 );
    }


    @Override
    public void end() {
      output.println( "Strings: " + string_map.size() );
      output.println( "Classes: " + class_dumps );
      output.println( "Instances: " + instance_dumps );
      output.println();

      final List<Pair<ID,Integer>> instance_counts =
        new ArrayList<Pair<ID, Integer>>( class_instances.size() );
      class_instances.forEachEntry( new TObjectIntProcedure<ID>() {
        @Override
        public boolean execute( ID id, int i ) {
          instance_counts.add( Pair.create( id, Integer.valueOf( i ) ) );
          return true;
        }
      } );
      Collections.sort( instance_counts, new Comparator<Pair<ID, Integer>>() {
        @Override
        public int compare( Pair<ID, Integer> o1, Pair<ID, Integer> o2 ) {
          return o2.getTwo().intValue() - o1.getTwo().intValue();
        }
      } );
      output.println( "Top Classes By Count" );
      int string_size = 10;
      for( int i = 0; i < 10 && i < instance_counts.size(); i++ ) {
        Pair<ID, Integer> p = instance_counts.get( i );

        String count_string = p.getTwo().toString();
        if ( i == 0 ) {
          string_size = count_string.length();
        }

        output.print( "   " );
        output.print( StringKit.ensureSize( count_string, string_size ) );
        output.print( " - " );
        output.println( string_map.get( class_name_map.get(
          p.getOne() ) ) );
      }

      final List<Pair<ID,Long>> instance_sizes =
        new ArrayList<Pair<ID, Long>>( class_aggregate_size.size() );
      class_aggregate_size.forEachEntry( new TObjectLongProcedure<ID>() {
        @Override
        public boolean execute( ID id, long l ) {
          instance_sizes.add( Pair.create( id, Long.valueOf( l ) ) );
          return true;
        }
      } );
      Collections.sort( instance_sizes, new Comparator<Pair<ID, Long>>() {
        @Override
        public int compare( Pair<ID, Long> o1, Pair<ID, Long> o2 ) {
          if ( o1.getTwo().longValue() > o2.getTwo().longValue() ) {
            return -1;
          }
          else if ( o1.getTwo().longValue() == o2.getTwo().longValue() ) {
            return 0;
          }
          else return 1;
        }
      } );

      output.println();
      output.println( "Top Classes By Size" );
      string_size = 10;
      for( int i = 0; i < 10 && i < instance_sizes.size(); i++ ) {
        Pair<ID, Long> p = instance_sizes.get( i );

        String count_string = p.getTwo().toString();
        if ( i == 0 ) {
          string_size = count_string.length();
        }

        output.print( "   " );
        output.print( StringKit.ensureSize( count_string, string_size ) );
        output.print( " - " );
        output.println( string_map.get( class_name_map.get(
          p.getOne() ) ) );
      }

      final List<Pair<Integer,Long>> trace_counts =
        new ArrayList<Pair<Integer, Long>>( MemoryAnalyzer.this.trace_counts.size() );
      MemoryAnalyzer.this.trace_counts.forEachEntry( new TIntLongProcedure() {
        @Override
        public boolean execute( int i, long l ) {
          trace_counts.add(
            Pair.create( Integer.valueOf( i ), Long.valueOf( l ) ) );
          return true;
        }
      } );
      Collections.sort( trace_counts, new Comparator<Pair<Integer, Long>>() {
        @Override
        public int compare( Pair<Integer, Long> o1, Pair<Integer, Long> o2 ) {
          if ( o1.getTwo().longValue() > o2.getTwo().longValue() ) {
            return -1;
          }
          else if ( o1.getTwo().longValue() == o2.getTwo().longValue() ) {
            return 0;
          }
          else return 1;
        }
      } );
      output.println();
      output.println( "Top Trace Counts" );
      string_size = 10;
      List<Integer> traces_to_print = new ArrayList<Integer>();
      for( int i = 0; i < 10 && i < trace_counts.size(); i++ ) {
        Pair<Integer, Long> p = trace_counts.get( i );

        String count_string = p.getTwo().toString();
        if ( i == 0 ) {
          string_size = count_string.length();
        }

        output.print( "   " );
        output.print( StringKit.ensureSize( count_string, string_size ) );
        output.print( " - " );
        output.println( Integer.toHexString( p.getOne().intValue() ) );

        traces_to_print.add( p.getOne() );
      }

      for( Integer trace_id : traces_to_print ) {
        output.println();
        output.println( "  Trace " + Integer.toHexString( trace_id.intValue() ) );
        List<ID> frames = stack_traces.get( trace_id.intValue() );
        if ( frames == null ) {
          output.print( "     No frames" );
        }
        else {
          for( ID frame : frames ) {
            StackTraceElement trace_element =
              MemoryAnalyzer.this.frames.get( frame );
            output.print( "     " );
            output.print( trace_element.getClassName() );
            output.print( '.' );
            output.print( trace_element.getMethodName() );
            output.print( " (" );
            output.print( trace_element.getFileName() );
            output.print( ':' );
            output.print( trace_element.getLineNumber() );
            output.println( ')' );
          }
        }
      }

      output.println();
      output.flush();
    }
  }
}
TOP

Related Classes of com.starlight.io.hprof.MemoryAnalyzer

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.