src/share/vm/memory/heapInspection.cpp

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.

@@ -127,11 +127,11 @@
   // This has the SIDE EFFECT of creating a KlassInfoEntry
   // for <k>, if one doesn't exist yet.
   _table->lookup(k);
 }
 
-KlassInfoTable::KlassInfoTable(bool need_class_stats) {
+KlassInfoTable::KlassInfoTable(bool add_all_classes) {
   _size_of_instances_in_words = 0;
   _size = 0;
   _ref = (HeapWord*) Universe::boolArrayKlassObj();
   _buckets =
     (KlassInfoBucket*)  AllocateHeap(sizeof(KlassInfoBucket) * _num_buckets,

@@ -139,11 +139,11 @@
   if (_buckets != NULL) {
     _size = _num_buckets;
     for (int index = 0; index < _size; index++) {
       _buckets[index].initialize();
     }
-    if (need_class_stats) {
+    if (add_all_classes) {
       AllClassesFinder finder(this);
       ClassLoaderDataGraph::classes_do(&finder);
     }
   }
 }

@@ -297,10 +297,123 @@
     st->print(",ClassLoader");
   }
   st->cr();
 }
 
+class HierarchyClosure : public KlassInfoClosure {
+private:
+  GrowableArray<KlassInfoEntry*> *_elements;
+public:
+  HierarchyClosure(GrowableArray<KlassInfoEntry*> *_elements) : _elements(_elements) {}
+
+  void do_cinfo(KlassInfoEntry* cie) {
+    // ignore array classes
+    if (cie->klass()->oop_is_instance()) {
+      _elements->append(cie);
+    }
+  }
+};
+
+void KlassHierarchy::print_class_hierarchy(outputStream* st) {
+  ResourceMark rm;
+  int i;
+  Stack <KlassInfoEntry*, mtClass> class_stack;
+  Stack <KlassInfoEntry*, mtClass> super_stack;
+  GrowableArray<KlassInfoEntry*> elements;
+
+  // Add all classes to the KlassInfoTable, which allows for quick lookup.
+  // A KlassInfoEntry will be created for each class.
+  KlassInfoTable cit(true);
+  if (cit.allocation_failed()) {
+    st->print_cr("WARNING: Ran out of C-heap; hierarchy not generated");
+    return;
+  }
+
+  // Add all created KlassInfoEntry instances to the elements array for easy
+  // iteration, and to allow each KlassInfoEntry instance to have a unique index.
+  HierarchyClosure hc(&elements);
+  cit.iterate(&hc);
+
+  // Set the index for each class
+  for(i=0; i < elements.length(); i++) {
+    elements.at(i)->set_index(i+1);
+  }
+
+  // Iterate over all the classes, adding each class to the subclass array of
+  // its superclass.
+  for(i=0; i < elements.length(); i++) {
+    KlassInfoEntry* e = (KlassInfoEntry*)elements.at(i);
+    const Klass* k = e->klass();
+    Klass* super = ((InstanceKlass*)k)->java_super();
+    if (super != NULL) {
+      KlassInfoEntry* super_e = cit.lookup(super);
+      assert(super_e != NULL, "could not lookup superclass");
+      e->set_super_index(super_e->index());
+      super_e->add_subclass(e);
+    }
+  }
+
+  // Now we do a depth first traversal of the class hierachry. The class_stack will
+  // maintain the list of classes we still need to process. Start things off
+  // by priming it with java.lang.Object.
+  KlassInfoEntry* jlo_cie = cit.lookup(SystemDictionary::Object_klass());
+  assert(jlo_cie != NULL, "could not lookup java.lang.Object");
+  class_stack.push(jlo_cie);
+
+  // Repeatedly pop the top item off the stack, print its class info,
+  // and push all of its subclasses on to the stack. Do this until there
+  // are no classes left on the stack.
+  //
+  // We also keep track of the stack of superclasses so we know
+  // all the current superclasses for the current class. This is how
+  // we determine the proper indentation when printing the class.
+  long curr_super_index = -1;
+  while (!class_stack.is_empty()) {
+    KlassInfoEntry* curr_cie = class_stack.pop();
+
+    // Make sure super_stack is current with the class we just popped.
+    while (curr_cie->super_index() != curr_super_index) {
+      assert(!super_stack.is_empty(), "super_stack should not be empty");
+      curr_super_index = super_stack.pop()->super_index();
+    }
+
+    print_class(st, curr_cie, &super_stack);
+
+    if (curr_cie->subclasses() != NULL) {
+      // Current class has subclasses, so push all of them onto the stack
+      for (int i = 0; i < curr_cie->subclasses()->length(); i++) {
+        class_stack.push(curr_cie->subclasses()->at(i));
+      }
+      // Add current class to superclass stack.
+      super_stack.push(curr_cie);
+      curr_super_index = curr_cie->index();
+    }
+  }
+
+  st->flush();
+}
+
+void KlassHierarchy::print_class(outputStream* st, KlassInfoEntry* cie,
+                                 Stack <KlassInfoEntry*, mtClass> *super_stack) {
+  ResourceMark rm;
+
+  // print indentation with proper indicators of superclass.
+  StackIterator<KlassInfoEntry*, mtClass> iter(*super_stack);
+  while (!iter.is_empty()) {
+    KlassInfoEntry* super_cie = iter.next();
+    st->print("|");
+    if (iter.is_empty()) {
+      st->print("--");
+    } else {
+      st->print("  ");
+    }
+  }
+
+  // print the class name
+  st->print("%s\n", cie->name());
+}
+
 void KlassInfoHisto::print_class_stats(outputStream* st,
                                       bool csv_format, const char *columns) {
   ResourceMark rm;
   KlassSizeStats sz, sz_sum;
   int i;

@@ -318,48 +431,52 @@
 
   for(i=0; i < elements()->length(); i++) {
     elements()->at(i)->set_index(i+1);
   }
 
+  // First iteration is for accumulating stats totals in colsum_table[].
+  // Second iteration is for printing stats for each class.
   for (int pass=1; pass<=2; pass++) {
     if (pass == 2) {
       print_title(st, csv_format, selected, width_table, name_table);
     }
     for(i=0; i < elements()->length(); i++) {
       KlassInfoEntry* e = (KlassInfoEntry*)elements()->at(i);
       const Klass* k = e->klass();
 
+      // Get the stats for this class
       memset(&sz, 0, sizeof(sz));
       sz._inst_count = e->count();
       sz._inst_bytes = HeapWordSize * e->words();
       k->collect_statistics(&sz);
       sz._total_bytes = sz._ro_bytes + sz._rw_bytes;
 
       if (pass == 1) {
+        // Add the stats for this class to the overall totals
         for (int c=0; c<KlassSizeStats::_num_columns; c++) {
           colsum_table[c] += col_table[c];
         }
       } else {
-        int super_index = -1;
+        // Print the stats for this class.
         if (k->oop_is_instance()) {
           Klass* super = ((InstanceKlass*)k)->java_super();
           if (super) {
             KlassInfoEntry* super_e = _cit->lookup(super);
             if (super_e) {
-              super_index = super_e->index();
+              e->set_super_index(super_e->index());
             }
           }
         }
 
         if (csv_format) {
-          st->print("%d,%d", e->index(), super_index);
+          st->print("%d,%d", e->index(), e->super_index());
           for (int c=0; c<KlassSizeStats::_num_columns; c++) {
             if (selected[c]) {st->print("," JULONG_FORMAT, col_table[c]);}
           }
           st->print(",%s",e->name());
         } else {
-          st->print("%5d %5d", e->index(), super_index);
+          st->print("%5d %5d", e->index(), e->super_index());
           for (int c=0; c<KlassSizeStats::_num_columns; c++) {
             if (selected[c]) {print_julong(st, width_table[c], col_table[c]);}
           }
           st->print(" %s", e->name());
         }

@@ -371,18 +488,21 @@
         st->cr();
       }
     }
 
     if (pass == 1) {
+      // Calculate the minimum width needed for the column by accounting for the
+      // column header width and the width of the largest value in the column.
       for (int c=0; c<KlassSizeStats::_num_columns; c++) {
         width_table[c] = col_width(colsum_table[c], name_table[c]);
       }
     }
   }
 
   sz_sum._inst_size = 0;
 
+  // Print the column totals.
   if (csv_format) {
     st->print(",");
     for (int c=0; c<KlassSizeStats::_num_columns; c++) {
       if (selected[c]) {st->print("," JULONG_FORMAT, colsum_table[c]);}
     }

@@ -512,10 +632,11 @@
     return;
   }
 
   KlassInfoTable cit(_print_class_stats);
   if (!cit.allocation_failed()) {
+    // populate table with object allocation info
     size_t missed_count = populate_table(&cit);
     if (missed_count != 0) {
       st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT
                    " total instances in data below",
                    missed_count);