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);