mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-11 14:11:36 +00:00
6479360: PrintClassHistogram improvements
Jcmd <pid> GC.class_stats (UnlockDiagnosticVMOptions) Reviewed-by: coleenp, hseigel, sla, acorn
This commit is contained in:
parent
19303cc71d
commit
93b845e21b
@ -724,13 +724,13 @@ void ClassLoaderDataGraph::dump_on(outputStream * const out) {
|
||||
}
|
||||
MetaspaceAux::dump(out);
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
void ClassLoaderData::print_value_on(outputStream* out) const {
|
||||
if (class_loader() == NULL) {
|
||||
out->print_cr("NULL class_loader");
|
||||
out->print("NULL class_loader");
|
||||
} else {
|
||||
out->print("class loader "PTR_FORMAT, this);
|
||||
class_loader()->print_value_on(out);
|
||||
}
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2013, 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
|
||||
@ -220,7 +220,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
void set_jmethod_ids(JNIMethodBlock* new_block) { _jmethod_ids = new_block; }
|
||||
|
||||
void print_value() { print_value_on(tty); }
|
||||
void print_value_on(outputStream* out) const PRODUCT_RETURN;
|
||||
void print_value_on(outputStream* out) const;
|
||||
void dump(outputStream * const out) PRODUCT_RETURN;
|
||||
void verify();
|
||||
const char* loader_name();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2013, 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
|
||||
@ -167,7 +167,9 @@ void VM_GC_HeapInspection::doit() {
|
||||
ch->collect_as_vm_thread(GCCause::_heap_inspection);
|
||||
}
|
||||
}
|
||||
HeapInspection::heap_inspection(_out, _need_prologue /* need_prologue */);
|
||||
HeapInspection inspect(_csv_format, _print_help, _print_class_stats,
|
||||
_columns);
|
||||
inspect.heap_inspection(_out, _need_prologue /* need_prologue */);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2013, 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
|
||||
@ -130,6 +130,10 @@ class VM_GC_HeapInspection: public VM_GC_Operation {
|
||||
outputStream* _out;
|
||||
bool _full_gc;
|
||||
bool _need_prologue;
|
||||
bool _csv_format; // "comma separated values" format for spreadsheet.
|
||||
bool _print_help;
|
||||
bool _print_class_stats;
|
||||
const char* _columns;
|
||||
public:
|
||||
VM_GC_HeapInspection(outputStream* out, bool request_full_gc,
|
||||
bool need_prologue) :
|
||||
@ -140,6 +144,10 @@ class VM_GC_HeapInspection: public VM_GC_Operation {
|
||||
_out = out;
|
||||
_full_gc = request_full_gc;
|
||||
_need_prologue = need_prologue;
|
||||
_csv_format = false;
|
||||
_print_help = false;
|
||||
_print_class_stats = false;
|
||||
_columns = NULL;
|
||||
}
|
||||
|
||||
~VM_GC_HeapInspection() {}
|
||||
@ -147,6 +155,10 @@ class VM_GC_HeapInspection: public VM_GC_Operation {
|
||||
virtual bool skip_operation() const;
|
||||
virtual bool doit_prologue();
|
||||
virtual void doit();
|
||||
void set_csv_format(bool value) {_csv_format = value;}
|
||||
void set_print_help(bool value) {_print_help = value;}
|
||||
void set_print_class_stats(bool value) {_print_class_stats = value;}
|
||||
void set_columns(const char* value) {_columns = value;}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2013, 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
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "gc_interface/collectedHeap.hpp"
|
||||
#include "memory/genCollectedHeap.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
@ -41,12 +42,24 @@ int KlassInfoEntry::compare(KlassInfoEntry* e1, KlassInfoEntry* e2) {
|
||||
} else if(e1->_instance_words < e2->_instance_words) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
// Sort alphabetically, note 'Z' < '[' < 'a', but it's better to group
|
||||
// the array classes before all the instance classes.
|
||||
ResourceMark rm;
|
||||
const char* name1 = e1->klass()->external_name();
|
||||
const char* name2 = e2->klass()->external_name();
|
||||
bool d1 = (name1[0] == '[');
|
||||
bool d2 = (name2[0] == '[');
|
||||
if (d1 && !d2) {
|
||||
return -1;
|
||||
} else if (d2 && !d1) {
|
||||
return 1;
|
||||
} else {
|
||||
return strcmp(name1, name2);
|
||||
}
|
||||
}
|
||||
|
||||
void KlassInfoEntry::print_on(outputStream* st) const {
|
||||
ResourceMark rm;
|
||||
const char* name;;
|
||||
const char* KlassInfoEntry::name() const {
|
||||
const char* name;
|
||||
if (_klass->name() != NULL) {
|
||||
name = _klass->external_name();
|
||||
} else {
|
||||
@ -60,11 +73,17 @@ void KlassInfoEntry::print_on(outputStream* st) const {
|
||||
if (_klass == Universe::longArrayKlassObj()) name = "<longArrayKlass>"; else
|
||||
name = "<no name>";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
void KlassInfoEntry::print_on(outputStream* st) const {
|
||||
ResourceMark rm;
|
||||
|
||||
// simplify the formatting (ILP32 vs LP64) - always cast the numbers to 64-bit
|
||||
st->print_cr(INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13) " %s",
|
||||
(jlong) _instance_count,
|
||||
(julong) _instance_words * HeapWordSize,
|
||||
name);
|
||||
name());
|
||||
}
|
||||
|
||||
KlassInfoEntry* KlassInfoBucket::lookup(Klass* const k) {
|
||||
@ -101,7 +120,14 @@ void KlassInfoBucket::empty() {
|
||||
}
|
||||
}
|
||||
|
||||
KlassInfoTable::KlassInfoTable(int size, HeapWord* ref) {
|
||||
void KlassInfoTable::AllClassesFinder::do_klass(Klass* k) {
|
||||
// This has the SIDE EFFECT of creating a KlassInfoEntry
|
||||
// for <k>, if one doesn't exist yet.
|
||||
_table->lookup(k);
|
||||
}
|
||||
|
||||
KlassInfoTable::KlassInfoTable(int size, HeapWord* ref,
|
||||
bool need_class_stats) {
|
||||
_size = 0;
|
||||
_ref = ref;
|
||||
_buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, size, mtInternal);
|
||||
@ -110,6 +136,10 @@ KlassInfoTable::KlassInfoTable(int size, HeapWord* ref) {
|
||||
for (int index = 0; index < _size; index++) {
|
||||
_buckets[index].initialize();
|
||||
}
|
||||
if (need_class_stats) {
|
||||
AllClassesFinder finder(this);
|
||||
ClassLoaderDataGraph::classes_do(&finder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,7 +195,8 @@ int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) {
|
||||
return (*e1)->compare(*e1,*e2);
|
||||
}
|
||||
|
||||
KlassInfoHisto::KlassInfoHisto(const char* title, int estimatedCount) :
|
||||
KlassInfoHisto::KlassInfoHisto(KlassInfoTable* cit, const char* title, int estimatedCount) :
|
||||
_cit(cit),
|
||||
_title(title) {
|
||||
_elements = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<KlassInfoEntry*>(estimatedCount,true);
|
||||
}
|
||||
@ -196,9 +227,205 @@ void KlassInfoHisto::print_elements(outputStream* st) const {
|
||||
total, totalw * HeapWordSize);
|
||||
}
|
||||
|
||||
void KlassInfoHisto::print_on(outputStream* st) const {
|
||||
st->print_cr("%s",title());
|
||||
print_elements(st);
|
||||
#define MAKE_COL_NAME(field, name, help) #name,
|
||||
#define MAKE_COL_HELP(field, name, help) help,
|
||||
|
||||
static const char *name_table[] = {
|
||||
HEAP_INSPECTION_COLUMNS_DO(MAKE_COL_NAME)
|
||||
};
|
||||
|
||||
static const char *help_table[] = {
|
||||
HEAP_INSPECTION_COLUMNS_DO(MAKE_COL_HELP)
|
||||
};
|
||||
|
||||
bool KlassInfoHisto::is_selected(const char *col_name) {
|
||||
if (_selected_columns == NULL) {
|
||||
return true;
|
||||
}
|
||||
if (strcmp(_selected_columns, col_name) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *start = strstr(_selected_columns, col_name);
|
||||
if (start == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The following must be true, because _selected_columns != col_name
|
||||
if (start > _selected_columns && start[-1] != ',') {
|
||||
return false;
|
||||
}
|
||||
char x = start[strlen(col_name)];
|
||||
if (x != ',' && x != '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void KlassInfoHisto::print_title(outputStream* st, bool csv_format,
|
||||
bool selected[], int width_table[],
|
||||
const char *name_table[]) {
|
||||
if (csv_format) {
|
||||
st->print("Index,Super");
|
||||
for (int c=0; c<KlassSizeStats::_num_columns; c++) {
|
||||
if (selected[c]) {st->print(",%s", name_table[c]);}
|
||||
}
|
||||
st->print(",ClassName");
|
||||
} else {
|
||||
st->print("Index Super");
|
||||
for (int c=0; c<KlassSizeStats::_num_columns; c++) {
|
||||
if (selected[c]) {st->print(str_fmt(width_table[c]), name_table[c]);}
|
||||
}
|
||||
st->print(" ClassName");
|
||||
}
|
||||
|
||||
if (is_selected("ClassLoader")) {
|
||||
st->print(",ClassLoader");
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
|
||||
void KlassInfoHisto::print_class_stats(outputStream* st,
|
||||
bool csv_format, const char *columns) {
|
||||
ResourceMark rm;
|
||||
KlassSizeStats sz, sz_sum;
|
||||
int i;
|
||||
julong *col_table = (julong*)(&sz);
|
||||
julong *colsum_table = (julong*)(&sz_sum);
|
||||
int width_table[KlassSizeStats::_num_columns];
|
||||
bool selected[KlassSizeStats::_num_columns];
|
||||
|
||||
_selected_columns = columns;
|
||||
|
||||
memset(&sz_sum, 0, sizeof(sz_sum));
|
||||
for (int c=0; c<KlassSizeStats::_num_columns; c++) {
|
||||
selected[c] = is_selected(name_table[c]);
|
||||
}
|
||||
|
||||
for(i=0; i < elements()->length(); i++) {
|
||||
elements()->at(i)->set_index(i+1);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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) {
|
||||
for (int c=0; c<KlassSizeStats::_num_columns; c++) {
|
||||
colsum_table[c] += col_table[c];
|
||||
}
|
||||
} else {
|
||||
int super_index = -1;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (csv_format) {
|
||||
st->print("%d,%d", e->index(), 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);
|
||||
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());
|
||||
}
|
||||
if (is_selected("ClassLoader")) {
|
||||
ClassLoaderData* loader_data = k->class_loader_data();
|
||||
st->print(",");
|
||||
loader_data->print_value_on(st);
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
|
||||
if (pass == 1) {
|
||||
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;
|
||||
|
||||
if (csv_format) {
|
||||
st->print(",");
|
||||
for (int c=0; c<KlassSizeStats::_num_columns; c++) {
|
||||
if (selected[c]) {st->print("," JULONG_FORMAT, colsum_table[c]);}
|
||||
}
|
||||
} else {
|
||||
st->print(" ");
|
||||
for (int c=0; c<KlassSizeStats::_num_columns; c++) {
|
||||
if (selected[c]) {print_julong(st, width_table[c], colsum_table[c]);}
|
||||
}
|
||||
st->print(" Total");
|
||||
if (sz_sum._total_bytes > 0) {
|
||||
st->cr();
|
||||
st->print(" ");
|
||||
for (int c=0; c<KlassSizeStats::_num_columns; c++) {
|
||||
if (selected[c]) {
|
||||
switch (c) {
|
||||
case KlassSizeStats::_index_inst_size:
|
||||
case KlassSizeStats::_index_inst_count:
|
||||
case KlassSizeStats::_index_method_count:
|
||||
st->print(str_fmt(width_table[c]), "-");
|
||||
break;
|
||||
default:
|
||||
{
|
||||
double perc = (double)(100) * (double)(colsum_table[c]) / (double)sz_sum._total_bytes;
|
||||
st->print(perc_fmt(width_table[c]), perc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
st->cr();
|
||||
|
||||
if (!csv_format) {
|
||||
print_title(st, csv_format, selected, width_table, name_table);
|
||||
}
|
||||
}
|
||||
|
||||
julong KlassInfoHisto::annotations_bytes(Array<AnnotationArray*>* p) const {
|
||||
julong bytes = 0;
|
||||
if (p != NULL) {
|
||||
for (int i = 0; i < p->length(); i++) {
|
||||
bytes += count_bytes_array(p->at(i));
|
||||
}
|
||||
bytes += count_bytes_array(p);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void KlassInfoHisto::print_histo_on(outputStream* st, bool print_stats,
|
||||
bool csv_format, const char *columns) {
|
||||
if (print_stats) {
|
||||
print_class_stats(st, csv_format, columns);
|
||||
} else {
|
||||
st->print_cr("%s",title());
|
||||
print_elements(st);
|
||||
}
|
||||
}
|
||||
|
||||
class HistoClosure : public KlassInfoClosure {
|
||||
@ -236,8 +463,26 @@ void HeapInspection::heap_inspection(outputStream* st, bool need_prologue) {
|
||||
CollectedHeap* heap = Universe::heap();
|
||||
bool is_shared_heap = false;
|
||||
|
||||
if (_print_help) {
|
||||
for (int c=0; c<KlassSizeStats::_num_columns; c++) {
|
||||
st->print("%s:\n\t", name_table[c]);
|
||||
const int max_col = 60;
|
||||
int col = 0;
|
||||
for (const char *p = help_table[c]; *p; p++,col++) {
|
||||
if (col >= max_col && *p == ' ') {
|
||||
st->print("\n\t");
|
||||
col = 0;
|
||||
} else {
|
||||
st->print("%c", *p);
|
||||
}
|
||||
}
|
||||
st->print_cr(".\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Collect klass instance info
|
||||
KlassInfoTable cit(KlassInfoTable::cit_size, ref);
|
||||
KlassInfoTable cit(KlassInfoTable::cit_size, ref, _print_class_stats);
|
||||
if (!cit.allocation_failed()) {
|
||||
// Iterate over objects in the heap
|
||||
RecordInstanceClosure ric(&cit);
|
||||
@ -252,14 +497,14 @@ void HeapInspection::heap_inspection(outputStream* st, bool need_prologue) {
|
||||
missed_count);
|
||||
}
|
||||
// Sort and print klass instance info
|
||||
KlassInfoHisto histo("\n"
|
||||
" num #instances #bytes class name\n"
|
||||
"----------------------------------------------",
|
||||
KlassInfoHisto::histo_initial_size);
|
||||
const char *title = "\n"
|
||||
" num #instances #bytes class name\n"
|
||||
"----------------------------------------------";
|
||||
KlassInfoHisto histo(&cit, title, KlassInfoHisto::histo_initial_size);
|
||||
HistoClosure hc(&histo);
|
||||
cit.iterate(&hc);
|
||||
histo.sort();
|
||||
histo.print_on(st);
|
||||
histo.print_histo_on(st, _print_class_stats, _csv_format, _columns);
|
||||
} else {
|
||||
st->print_cr("WARNING: Ran out of C-heap; histogram not generated");
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2013, 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
|
||||
@ -27,6 +27,7 @@
|
||||
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/annotations.hpp"
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
|
||||
@ -44,16 +45,144 @@
|
||||
// to KlassInfoEntry's and is used to sort
|
||||
// the entries.
|
||||
|
||||
#define HEAP_INSPECTION_COLUMNS_DO(f) \
|
||||
f(inst_size, InstSize, \
|
||||
"Size of each object instance of the Java class") \
|
||||
f(inst_count, InstCount, \
|
||||
"Number of object instances of the Java class") \
|
||||
f(inst_bytes, InstBytes, \
|
||||
"This is usually (InstSize * InstNum). The only exception is " \
|
||||
"java.lang.Class, whose InstBytes also includes the slots " \
|
||||
"used to store static fields. InstBytes is not counted in " \
|
||||
"ROAll, RWAll or Total") \
|
||||
f(mirror_bytes, Mirror, \
|
||||
"Size of the Klass::java_mirror() object") \
|
||||
f(klass_bytes, KlassBytes, \
|
||||
"Size of the InstanceKlass or ArrayKlass for this class. " \
|
||||
"Note that this includes VTab, ITab, OopMap") \
|
||||
f(secondary_supers_bytes, K_secondary_supers, \
|
||||
"Number of bytes used by the Klass::secondary_supers() array") \
|
||||
f(vtab_bytes, VTab, \
|
||||
"Size of the embedded vtable in InstanceKlass") \
|
||||
f(itab_bytes, ITab, \
|
||||
"Size of the embedded itable in InstanceKlass") \
|
||||
f(nonstatic_oopmap_bytes, OopMap, \
|
||||
"Size of the embedded nonstatic_oop_map in InstanceKlass") \
|
||||
f(methods_array_bytes, IK_methods, \
|
||||
"Number of bytes used by the InstanceKlass::methods() array") \
|
||||
f(method_ordering_bytes, IK_method_ordering, \
|
||||
"Number of bytes used by the InstanceKlass::method_ordering() array") \
|
||||
f(local_interfaces_bytes, IK_local_interfaces, \
|
||||
"Number of bytes used by the InstanceKlass::local_interfaces() array") \
|
||||
f(transitive_interfaces_bytes, IK_transitive_interfaces, \
|
||||
"Number of bytes used by the InstanceKlass::transitive_interfaces() array") \
|
||||
f(fields_bytes, IK_fields, \
|
||||
"Number of bytes used by the InstanceKlass::fields() array") \
|
||||
f(inner_classes_bytes, IK_inner_classes, \
|
||||
"Number of bytes used by the InstanceKlass::inner_classes() array") \
|
||||
f(signers_bytes, IK_signers, \
|
||||
"Number of bytes used by the InstanceKlass::singers() array") \
|
||||
f(class_annotations_bytes, class_annotations, \
|
||||
"Size of class annotations") \
|
||||
f(fields_annotations_bytes, fields_annotations, \
|
||||
"Size of field annotations") \
|
||||
f(methods_annotations_bytes, methods_annotations, \
|
||||
"Size of method annotations") \
|
||||
f(methods_parameter_annotations_bytes, methods_parameter_annotations, \
|
||||
"Size of method parameter annotations") \
|
||||
f(methods_default_annotations_bytes, methods_default_annotations, \
|
||||
"Size of methods default annotations") \
|
||||
f(type_annotations_bytes, type_annotations, \
|
||||
"Size of type annotations") \
|
||||
f(annotations_bytes, annotations, \
|
||||
"Size of all annotations") \
|
||||
f(cp_bytes, Cp, \
|
||||
"Size of InstanceKlass::constants()") \
|
||||
f(cp_tags_bytes, CpTags, \
|
||||
"Size of InstanceKlass::constants()->tags()") \
|
||||
f(cp_cache_bytes, CpCache, \
|
||||
"Size of InstanceKlass::constants()->cache()") \
|
||||
f(cp_operands_bytes, CpOperands, \
|
||||
"Size of InstanceKlass::constants()->operands()") \
|
||||
f(cp_refmap_bytes, CpRefMap, \
|
||||
"Size of InstanceKlass::constants()->reference_map()") \
|
||||
f(cp_all_bytes, CpAll, \
|
||||
"Sum of Cp + CpTags + CpCache + CpOperands + CpRefMap") \
|
||||
f(method_count, MethodCount, \
|
||||
"Number of methods in this class") \
|
||||
f(method_bytes, MethodBytes, \
|
||||
"Size of the Method object") \
|
||||
f(const_method_bytes, ConstMethod, \
|
||||
"Size of the ConstMethod object") \
|
||||
f(method_data_bytes, MethodData, \
|
||||
"Size of the MethodData object") \
|
||||
f(stackmap_bytes, StackMap, \
|
||||
"Size of the stackmap_data") \
|
||||
f(bytecode_bytes, Bytecodes, \
|
||||
"Of the MethodBytes column, how much are the space taken up by bytecodes") \
|
||||
f(method_all_bytes, MethodAll, \
|
||||
"Sum of MethodBytes + Constmethod + Stackmap + Methoddata") \
|
||||
f(ro_bytes, ROAll, \
|
||||
"Size of all class meta data that could (potentially) be placed " \
|
||||
"in read-only memory. (This could change with CDS design)") \
|
||||
f(rw_bytes, RWAll, \
|
||||
"Size of all class meta data that must be placed in read/write " \
|
||||
"memory. (This could change with CDS design) ") \
|
||||
f(total_bytes, Total, \
|
||||
"ROAll + RWAll. Note that this does NOT include InstBytes.")
|
||||
|
||||
// Size statistics for a Klass - filled in by Klass::collect_statistics()
|
||||
class KlassSizeStats {
|
||||
public:
|
||||
#define COUNT_KLASS_SIZE_STATS_FIELD(field, name, help) _index_ ## field,
|
||||
#define DECLARE_KLASS_SIZE_STATS_FIELD(field, name, help) julong _ ## field;
|
||||
|
||||
enum {
|
||||
HEAP_INSPECTION_COLUMNS_DO(COUNT_KLASS_SIZE_STATS_FIELD)
|
||||
_num_columns
|
||||
};
|
||||
|
||||
HEAP_INSPECTION_COLUMNS_DO(DECLARE_KLASS_SIZE_STATS_FIELD)
|
||||
|
||||
static int count(oop x) {
|
||||
return (HeapWordSize * ((x) ? (x)->size() : 0));
|
||||
}
|
||||
|
||||
static int count_array(objArrayOop x) {
|
||||
return (HeapWordSize * ((x) ? (x)->size() : 0));
|
||||
}
|
||||
|
||||
template <class T> static int count(T* x) {
|
||||
return (HeapWordSize * ((x) ? (x)->size() : 0));
|
||||
}
|
||||
|
||||
template <class T> static int count_array(T* x) {
|
||||
if (x == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (x->length() == 0) {
|
||||
// This is a shared array, e.g., Universe::the_empty_int_array(). Don't
|
||||
// count it to avoid double-counting.
|
||||
return 0;
|
||||
}
|
||||
return HeapWordSize * x->size();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class KlassInfoEntry: public CHeapObj<mtInternal> {
|
||||
private:
|
||||
KlassInfoEntry* _next;
|
||||
Klass* _klass;
|
||||
long _instance_count;
|
||||
size_t _instance_words;
|
||||
long _index;
|
||||
|
||||
public:
|
||||
KlassInfoEntry(Klass* k, KlassInfoEntry* next) :
|
||||
_klass(k), _instance_count(0), _instance_words(0), _next(next)
|
||||
_klass(k), _instance_count(0), _instance_words(0), _next(next), _index(-1)
|
||||
{}
|
||||
KlassInfoEntry* next() { return _next; }
|
||||
bool is_equal(Klass* k) { return k == _klass; }
|
||||
@ -62,8 +191,11 @@ class KlassInfoEntry: public CHeapObj<mtInternal> {
|
||||
void set_count(long ct) { _instance_count = ct; }
|
||||
size_t words() { return _instance_words; }
|
||||
void set_words(size_t wds) { _instance_words = wds; }
|
||||
void set_index(long index) { _index = index; }
|
||||
long index() { return _index; }
|
||||
int compare(KlassInfoEntry* e1, KlassInfoEntry* e2);
|
||||
void print_on(outputStream* st) const;
|
||||
const char* name() const;
|
||||
};
|
||||
|
||||
class KlassInfoClosure: public StackObj {
|
||||
@ -95,45 +227,132 @@ class KlassInfoTable: public StackObj {
|
||||
|
||||
KlassInfoBucket* _buckets;
|
||||
uint hash(Klass* p);
|
||||
KlassInfoEntry* lookup(Klass* const k);
|
||||
KlassInfoEntry* lookup(Klass* const k); // allocates if not found!
|
||||
|
||||
class AllClassesFinder : public KlassClosure {
|
||||
KlassInfoTable *_table;
|
||||
public:
|
||||
AllClassesFinder(KlassInfoTable* table) : _table(table) {}
|
||||
virtual void do_klass(Klass* k);
|
||||
};
|
||||
|
||||
public:
|
||||
// Table size
|
||||
enum {
|
||||
cit_size = 20011
|
||||
};
|
||||
KlassInfoTable(int size, HeapWord* ref);
|
||||
KlassInfoTable(int size, HeapWord* ref, bool need_class_stats);
|
||||
~KlassInfoTable();
|
||||
bool record_instance(const oop obj);
|
||||
void iterate(KlassInfoClosure* cic);
|
||||
bool allocation_failed() { return _buckets == NULL; }
|
||||
|
||||
friend class KlassInfoHisto;
|
||||
};
|
||||
|
||||
class KlassInfoHisto : public StackObj {
|
||||
private:
|
||||
KlassInfoTable *_cit;
|
||||
GrowableArray<KlassInfoEntry*>* _elements;
|
||||
GrowableArray<KlassInfoEntry*>* elements() const { return _elements; }
|
||||
const char* _title;
|
||||
const char* title() const { return _title; }
|
||||
static int sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2);
|
||||
void print_elements(outputStream* st) const;
|
||||
void print_class_stats(outputStream* st, bool csv_format, const char *columns);
|
||||
julong annotations_bytes(Array<AnnotationArray*>* p) const;
|
||||
const char *_selected_columns;
|
||||
bool is_selected(const char *col_name);
|
||||
void print_title(outputStream* st, bool csv_format,
|
||||
bool selected_columns_table[], int width_table[],
|
||||
const char *name_table[]);
|
||||
|
||||
template <class T> static int count_bytes(T* x) {
|
||||
return (HeapWordSize * ((x) ? (x)->size() : 0));
|
||||
}
|
||||
|
||||
template <class T> static int count_bytes_array(T* x) {
|
||||
if (x == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (x->length() == 0) {
|
||||
// This is a shared array, e.g., Universe::the_empty_int_array(). Don't
|
||||
// count it to avoid double-counting.
|
||||
return 0;
|
||||
}
|
||||
return HeapWordSize * x->size();
|
||||
}
|
||||
|
||||
// returns a format string to print a julong with the given width. E.g,
|
||||
// printf(num_fmt(6), julong(10)) would print out the number 10 with 4
|
||||
// leading spaces.
|
||||
static void print_julong(outputStream* st, int width, julong n) {
|
||||
int num_spaces = width - julong_width(n);
|
||||
if (num_spaces > 0) {
|
||||
st->print(str_fmt(num_spaces), "");
|
||||
}
|
||||
st->print(JULONG_FORMAT, n);
|
||||
}
|
||||
|
||||
static char* perc_fmt(int width) {
|
||||
static char buf[32];
|
||||
jio_snprintf(buf, sizeof(buf), "%%%d.1f%%%%", width-1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char* str_fmt(int width) {
|
||||
static char buf[32];
|
||||
jio_snprintf(buf, sizeof(buf), "%%%ds", width);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int julong_width(julong n) {
|
||||
if (n == 0) {
|
||||
return 1;
|
||||
}
|
||||
int w = 0;
|
||||
while (n > 0) {
|
||||
n /= 10;
|
||||
w += 1;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
static int col_width(julong n, const char *name) {
|
||||
int w = julong_width(n);
|
||||
int min = (int)(strlen(name));
|
||||
if (w < min) {
|
||||
w = min;
|
||||
}
|
||||
// add a leading space for separation.
|
||||
return w + 1;
|
||||
}
|
||||
|
||||
public:
|
||||
enum {
|
||||
histo_initial_size = 1000
|
||||
};
|
||||
KlassInfoHisto(const char* title,
|
||||
KlassInfoHisto(KlassInfoTable* cit, const char* title,
|
||||
int estimatedCount);
|
||||
~KlassInfoHisto();
|
||||
void add(KlassInfoEntry* cie);
|
||||
void print_on(outputStream* st) const;
|
||||
void print_histo_on(outputStream* st, bool print_class_stats, bool csv_format, const char *columns);
|
||||
void sort();
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
class HeapInspection : public AllStatic {
|
||||
class HeapInspection : public StackObj {
|
||||
bool _csv_format; // "comma separated values" format for spreadsheet.
|
||||
bool _print_help;
|
||||
bool _print_class_stats;
|
||||
const char* _columns;
|
||||
public:
|
||||
static void heap_inspection(outputStream* st, bool need_prologue) NOT_SERVICES_RETURN;
|
||||
HeapInspection(bool csv_format, bool print_help,
|
||||
bool print_class_stats, const char *columns) :
|
||||
_csv_format(csv_format), _print_help(print_help),
|
||||
_print_class_stats(print_class_stats), _columns(columns) {}
|
||||
void heap_inspection(outputStream* st, bool need_prologue) NOT_SERVICES_RETURN;
|
||||
static void find_instances_at_safepoint(Klass* k, GrowableArray<oop>* result) NOT_SERVICES_RETURN;
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2013, 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
|
||||
@ -24,6 +24,7 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "oops/annotations.hpp"
|
||||
@ -114,6 +115,50 @@ void Annotations::print_value_on(outputStream* st) const {
|
||||
st->print("Anotations(" INTPTR_FORMAT ")", this);
|
||||
}
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
// Size Statistics
|
||||
|
||||
julong Annotations::count_bytes(Array<AnnotationArray*>* p) {
|
||||
julong bytes = 0;
|
||||
if (p != NULL) {
|
||||
for (int i = 0; i < p->length(); i++) {
|
||||
bytes += KlassSizeStats::count_array(p->at(i));
|
||||
}
|
||||
bytes += KlassSizeStats::count_array(p);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void Annotations::collect_statistics(KlassSizeStats *sz) const {
|
||||
sz->_annotations_bytes = sz->count(this);
|
||||
sz->_class_annotations_bytes = sz->count(class_annotations());
|
||||
sz->_fields_annotations_bytes = count_bytes(fields_annotations());
|
||||
sz->_methods_annotations_bytes = count_bytes(methods_annotations());
|
||||
sz->_methods_parameter_annotations_bytes =
|
||||
count_bytes(methods_parameter_annotations());
|
||||
sz->_methods_default_annotations_bytes =
|
||||
count_bytes(methods_default_annotations());
|
||||
|
||||
const Annotations* type_anno = type_annotations();
|
||||
if (type_anno != NULL) {
|
||||
sz->_type_annotations_bytes = sz->count(type_anno);
|
||||
sz->_type_annotations_bytes += sz->count(type_anno->class_annotations());
|
||||
sz->_type_annotations_bytes += count_bytes(type_anno->fields_annotations());
|
||||
sz->_type_annotations_bytes += count_bytes(type_anno->methods_annotations());
|
||||
}
|
||||
|
||||
sz->_annotations_bytes +=
|
||||
sz->_class_annotations_bytes +
|
||||
sz->_fields_annotations_bytes +
|
||||
sz->_methods_annotations_bytes +
|
||||
sz->_methods_parameter_annotations_bytes +
|
||||
sz->_methods_default_annotations_bytes +
|
||||
sz->_type_annotations_bytes;
|
||||
|
||||
sz->_ro_bytes += sz->_annotations_bytes;
|
||||
}
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
#define BULLET " - "
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2013, 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
|
||||
@ -34,6 +34,7 @@
|
||||
|
||||
class ClassLoaderData;
|
||||
class outputStream;
|
||||
class KlassSizeStats;
|
||||
|
||||
typedef Array<u1> AnnotationArray;
|
||||
|
||||
@ -82,7 +83,12 @@ class Annotations: public MetaspaceObj {
|
||||
Array<AnnotationArray*>* mda, TRAPS);
|
||||
void deallocate_contents(ClassLoaderData* loader_data);
|
||||
DEBUG_ONLY(bool on_stack() { return false; }) // for template
|
||||
|
||||
// Sizing (in words)
|
||||
static int size() { return sizeof(Annotations) / wordSize; }
|
||||
#if INCLUDE_SERVICES
|
||||
void collect_statistics(KlassSizeStats *sz) const;
|
||||
#endif
|
||||
|
||||
// Constructor to initialize to null
|
||||
Annotations() : _class_annotations(NULL),
|
||||
@ -142,7 +148,7 @@ class Annotations: public MetaspaceObj {
|
||||
void set_methods_annotations_of(instanceKlassHandle ik,
|
||||
int idnum, AnnotationArray* anno,
|
||||
Array<AnnotationArray*>** md_p, TRAPS);
|
||||
|
||||
static julong count_bytes(Array<AnnotationArray*>* p);
|
||||
public:
|
||||
const char* internal_name() const { return "{constant pool}"; }
|
||||
#ifndef PRODUCT
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, 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
|
||||
@ -106,6 +106,14 @@ class ArrayKlass: public Klass {
|
||||
static int header_size() { return sizeof(ArrayKlass)/HeapWordSize; }
|
||||
static int static_size(int header_size);
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
virtual void collect_statistics(KlassSizeStats *sz) const {
|
||||
Klass::collect_statistics(sz);
|
||||
// Do nothing for now, but remember to modify if you add new
|
||||
// stuff to ArrayKlass.
|
||||
}
|
||||
#endif
|
||||
|
||||
// Java vtable
|
||||
klassVtable* vtable() const; // return new klassVtable
|
||||
int vtable_length() const { return _vtable_len; }
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2013, 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
|
||||
@ -25,6 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "memory/gcLocker.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "oops/constMethod.hpp"
|
||||
#include "oops/method.hpp"
|
||||
@ -330,6 +331,18 @@ void ConstMethod::print_value_on(outputStream* st) const {
|
||||
method()->print_value_on(st);
|
||||
}
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
// Size Statistics
|
||||
void ConstMethod::collect_statistics(KlassSizeStats *sz) const {
|
||||
int n1, n2, n3;
|
||||
sz->_const_method_bytes += (n1 = sz->count(this));
|
||||
sz->_bytecode_bytes += (n2 = code_size());
|
||||
sz->_stackmap_bytes += (n3 = sz->count_array(stackmap_data()));
|
||||
|
||||
sz->_method_all_bytes += n1 + n3; // note: n2 is part of n3
|
||||
sz->_ro_bytes += n1 + n3;
|
||||
}
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
// Verification
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2013, 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
|
||||
@ -130,6 +130,7 @@ class MethodParametersElement VALUE_OBJ_CLASS_SPEC {
|
||||
u2 flags_lo;
|
||||
};
|
||||
|
||||
class KlassSizeStats;
|
||||
|
||||
class ConstMethod : public MetaspaceObj {
|
||||
friend class VMStructs;
|
||||
@ -320,6 +321,9 @@ public:
|
||||
|
||||
int size() const { return _constMethod_size;}
|
||||
void set_constMethod_size(int size) { _constMethod_size = size; }
|
||||
#if INCLUDE_SERVICES
|
||||
void collect_statistics(KlassSizeStats *sz) const;
|
||||
#endif
|
||||
|
||||
// code size
|
||||
int code_size() const { return _code_size; }
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "oops/constantPool.hpp"
|
||||
@ -1946,6 +1947,20 @@ void ConstantPool::print_value_on(outputStream* st) const {
|
||||
}
|
||||
}
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
// Size Statistics
|
||||
void ConstantPool::collect_statistics(KlassSizeStats *sz) const {
|
||||
sz->_cp_all_bytes += (sz->_cp_bytes = sz->count(this));
|
||||
sz->_cp_all_bytes += (sz->_cp_tags_bytes = sz->count_array(tags()));
|
||||
sz->_cp_all_bytes += (sz->_cp_cache_bytes = sz->count(cache()));
|
||||
sz->_cp_all_bytes += (sz->_cp_operands_bytes = sz->count_array(operands()));
|
||||
sz->_cp_all_bytes += (sz->_cp_refmap_bytes = sz->count_array(reference_map()));
|
||||
|
||||
sz->_ro_bytes += sz->_cp_operands_bytes + sz->_cp_tags_bytes +
|
||||
sz->_cp_refmap_bytes;
|
||||
sz->_rw_bytes += sz->_cp_bytes + sz->_cp_cache_bytes;
|
||||
}
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
// Verification
|
||||
|
||||
|
||||
@ -80,6 +80,7 @@ class CPSlot VALUE_OBJ_CLASS_SPEC {
|
||||
}
|
||||
};
|
||||
|
||||
class KlassSizeStats;
|
||||
class ConstantPool : public Metadata {
|
||||
friend class VMStructs;
|
||||
friend class BytecodeInterpreter; // Directly extracts an oop in the pool for fast instanceof/checkcast
|
||||
@ -684,9 +685,13 @@ class ConstantPool : public Metadata {
|
||||
return 0 <= index && index < length();
|
||||
}
|
||||
|
||||
// Sizing (in words)
|
||||
static int header_size() { return sizeof(ConstantPool)/HeapWordSize; }
|
||||
static int size(int length) { return align_object_size(header_size() + length); }
|
||||
int size() const { return size(length()); }
|
||||
#if INCLUDE_SERVICES
|
||||
void collect_statistics(KlassSizeStats *sz) const;
|
||||
#endif
|
||||
|
||||
friend class ClassFileParser;
|
||||
friend class SystemDictionary;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, 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
|
||||
@ -34,6 +34,7 @@
|
||||
#include "interpreter/rewriter.hpp"
|
||||
#include "jvmtifiles/jvmti.h"
|
||||
#include "memory/genOopClosures.inline.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "oops/fieldStreams.hpp"
|
||||
@ -2960,6 +2961,52 @@ const char* InstanceKlass::internal_name() const {
|
||||
return external_name();
|
||||
}
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
// Size Statistics
|
||||
void InstanceKlass::collect_statistics(KlassSizeStats *sz) const {
|
||||
Klass::collect_statistics(sz);
|
||||
|
||||
sz->_inst_size = HeapWordSize * size_helper();
|
||||
sz->_vtab_bytes = HeapWordSize * align_object_offset(vtable_length());
|
||||
sz->_itab_bytes = HeapWordSize * align_object_offset(itable_length());
|
||||
sz->_nonstatic_oopmap_bytes = HeapWordSize *
|
||||
((is_interface() || is_anonymous()) ?
|
||||
align_object_offset(nonstatic_oop_map_size()) :
|
||||
nonstatic_oop_map_size());
|
||||
|
||||
int n = 0;
|
||||
n += (sz->_methods_array_bytes = sz->count_array(methods()));
|
||||
n += (sz->_method_ordering_bytes = sz->count_array(method_ordering()));
|
||||
n += (sz->_local_interfaces_bytes = sz->count_array(local_interfaces()));
|
||||
n += (sz->_transitive_interfaces_bytes = sz->count_array(transitive_interfaces()));
|
||||
n += (sz->_signers_bytes = sz->count_array(signers()));
|
||||
n += (sz->_fields_bytes = sz->count_array(fields()));
|
||||
n += (sz->_inner_classes_bytes = sz->count_array(inner_classes()));
|
||||
sz->_ro_bytes += n;
|
||||
|
||||
const ConstantPool* cp = constants();
|
||||
if (cp) {
|
||||
cp->collect_statistics(sz);
|
||||
}
|
||||
|
||||
const Annotations* anno = annotations();
|
||||
if (anno) {
|
||||
anno->collect_statistics(sz);
|
||||
}
|
||||
|
||||
const Array<Method*>* methods_array = methods();
|
||||
if (methods()) {
|
||||
for (int i = 0; i < methods_array->length(); i++) {
|
||||
Method* method = methods_array->at(i);
|
||||
if (method) {
|
||||
sz->_method_count ++;
|
||||
method->collect_statistics(sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
// Verification
|
||||
|
||||
class VerifyFieldClosure: public OopClosure {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, 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
|
||||
@ -826,6 +826,9 @@ class InstanceKlass: public Klass {
|
||||
is_interface(),
|
||||
is_anonymous());
|
||||
}
|
||||
#if INCLUDE_SERVICES
|
||||
virtual void collect_statistics(KlassSizeStats *sz) const;
|
||||
#endif
|
||||
|
||||
static int vtable_start_offset() { return header_size(); }
|
||||
static int vtable_length_offset() { return offset_of(InstanceKlass, _vtable_len) / HeapWordSize; }
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, 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
|
||||
@ -29,6 +29,7 @@
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "gc_implementation/shared/markSweep.inline.hpp"
|
||||
#include "gc_interface/collectedHeap.inline.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
@ -624,6 +625,17 @@ void Klass::oop_print_value_on(oop obj, outputStream* st) {
|
||||
obj->print_address_on(st);
|
||||
}
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
// Size Statistics
|
||||
void Klass::collect_statistics(KlassSizeStats *sz) const {
|
||||
sz->_klass_bytes = sz->count(this);
|
||||
sz->_mirror_bytes = sz->count(java_mirror());
|
||||
sz->_secondary_supers_bytes = sz->count_array(secondary_supers());
|
||||
|
||||
sz->_ro_bytes += sz->_secondary_supers_bytes;
|
||||
sz->_rw_bytes += sz->_klass_bytes + sz->_mirror_bytes;
|
||||
}
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
// Verification
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, 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
|
||||
@ -91,6 +91,7 @@ template <class T> class GrowableArray;
|
||||
class ClassLoaderData;
|
||||
class klassVtable;
|
||||
class ParCompactionManager;
|
||||
class KlassSizeStats;
|
||||
|
||||
class Klass : public Metadata {
|
||||
friend class VMStructs;
|
||||
@ -477,6 +478,9 @@ class Klass : public Metadata {
|
||||
|
||||
// Size of klass in word size.
|
||||
virtual int size() const = 0;
|
||||
#if INCLUDE_SERVICES
|
||||
virtual void collect_statistics(KlassSizeStats *sz) const;
|
||||
#endif
|
||||
|
||||
// Returns the Java name for a class (Resource allocated)
|
||||
// For arrays, this returns the name of the element with a leading '['.
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
#include "interpreter/oopMapCache.hpp"
|
||||
#include "memory/gcLocker.hpp"
|
||||
#include "memory/generation.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "oops/constMethod.hpp"
|
||||
@ -1954,6 +1955,22 @@ void Method::print_value_on(outputStream* st) const {
|
||||
if (WizardMode && code() != NULL) st->print(" ((nmethod*)%p)", code());
|
||||
}
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
// Size Statistics
|
||||
void Method::collect_statistics(KlassSizeStats *sz) const {
|
||||
int mysize = sz->count(this);
|
||||
sz->_method_bytes += mysize;
|
||||
sz->_method_all_bytes += mysize;
|
||||
sz->_rw_bytes += mysize;
|
||||
|
||||
if (constMethod()) {
|
||||
constMethod()->collect_statistics(sz);
|
||||
}
|
||||
if (method_data()) {
|
||||
method_data()->collect_statistics(sz);
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
// Verification
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, 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
|
||||
@ -101,6 +101,7 @@ class LocalVariableTableElement;
|
||||
class AdapterHandlerEntry;
|
||||
class MethodData;
|
||||
class ConstMethod;
|
||||
class KlassSizeStats;
|
||||
|
||||
class Method : public Metadata {
|
||||
friend class VMStructs;
|
||||
@ -593,6 +594,9 @@ class Method : public Metadata {
|
||||
static int header_size() { return sizeof(Method)/HeapWordSize; }
|
||||
static int size(bool is_native);
|
||||
int size() const { return method_size(); }
|
||||
#if INCLUDE_SERVICES
|
||||
void collect_statistics(KlassSizeStats *sz) const;
|
||||
#endif
|
||||
|
||||
// interpreter support
|
||||
static ByteSize const_offset() { return byte_offset_of(Method, _constMethod ); }
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2013, 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
|
||||
@ -27,6 +27,7 @@
|
||||
#include "interpreter/bytecode.hpp"
|
||||
#include "interpreter/bytecodeStream.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "oops/methodData.hpp"
|
||||
#include "prims/jvmtiRedefineClasses.hpp"
|
||||
#include "runtime/compilationPolicy.hpp"
|
||||
@ -859,6 +860,15 @@ void MethodData::print_data_on(outputStream* st) const {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
// Size Statistics
|
||||
void MethodData::collect_statistics(KlassSizeStats *sz) const {
|
||||
int n = sz->count(this);
|
||||
sz->_method_data_bytes += n;
|
||||
sz->_method_all_bytes += n;
|
||||
sz->_rw_bytes += n;
|
||||
}
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
// Verification
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2013, 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
|
||||
@ -32,6 +32,7 @@
|
||||
#include "runtime/orderAccess.hpp"
|
||||
|
||||
class BytecodeStream;
|
||||
class KlassSizeStats;
|
||||
|
||||
// The MethodData object collects counts and other profile information
|
||||
// during zeroth-tier (interpretive) and first-tier execution.
|
||||
@ -1289,6 +1290,9 @@ public:
|
||||
// My size
|
||||
int size_in_bytes() const { return _size; }
|
||||
int size() const { return align_object_size(align_size_up(_size, BytesPerWord)/BytesPerWord); }
|
||||
#if INCLUDE_SERVICES
|
||||
void collect_statistics(KlassSizeStats *sz) const;
|
||||
#endif
|
||||
|
||||
int creation_mileage() const { return _creation_mileage; }
|
||||
void set_creation_mileage(int x) { _creation_mileage = x; }
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2013, 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
|
||||
@ -43,12 +43,12 @@ void DCmdRegistrant::register_dcmds(){
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(true, false));
|
||||
#if INCLUDE_SERVICES // Heap dumping supported
|
||||
#if INCLUDE_SERVICES // Heap dumping/inspection supported
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(true, false));
|
||||
#endif // INCLUDE_SERVICES
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(true, false));
|
||||
#endif // INCLUDE_SERVICES
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(true, false));
|
||||
|
||||
//Enhanced JMX Agent Support
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartRemoteDCmd>(true,false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartLocalDCmd>(true,false));
|
||||
@ -252,7 +252,7 @@ void RunFinalizationDCmd::execute(TRAPS) {
|
||||
vmSymbols::void_method_signature(), CHECK);
|
||||
}
|
||||
|
||||
#if INCLUDE_SERVICES // Heap dumping supported
|
||||
#if INCLUDE_SERVICES // Heap dumping/inspection supported
|
||||
HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) :
|
||||
DCmdWithParser(output, heap),
|
||||
_filename("filename","Name of the dump file", "STRING",true),
|
||||
@ -292,7 +292,6 @@ int HeapDumpDCmd::num_arguments() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
ClassHistogramDCmd::ClassHistogramDCmd(outputStream* output, bool heap) :
|
||||
DCmdWithParser(output, heap),
|
||||
@ -319,6 +318,65 @@ int ClassHistogramDCmd::num_arguments() {
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFAULT_COLUMNS "InstBytes,KlassBytes,CpAll,annotations,MethodCount,Bytecodes,MethodAll,ROAll,RWAll,Total"
|
||||
ClassStatsDCmd::ClassStatsDCmd(outputStream* output, bool heap) :
|
||||
DCmdWithParser(output, heap),
|
||||
_csv("-csv", "Print in CSV (comma-separated values) format for spreadsheets",
|
||||
"BOOLEAN", false, "false"),
|
||||
_all("-all", "Show all columns",
|
||||
"BOOLEAN", false, "false"),
|
||||
_help("-help", "Show meaning of all the columns",
|
||||
"BOOLEAN", false, "false"),
|
||||
_columns("columns", "Comma-separated list of all the columns to show. "
|
||||
"If not specified, the following columns are shown: " DEFAULT_COLUMNS,
|
||||
"STRING", false) {
|
||||
_dcmdparser.add_dcmd_option(&_all);
|
||||
_dcmdparser.add_dcmd_option(&_csv);
|
||||
_dcmdparser.add_dcmd_option(&_help);
|
||||
_dcmdparser.add_dcmd_argument(&_columns);
|
||||
}
|
||||
|
||||
void ClassStatsDCmd::execute(TRAPS) {
|
||||
if (!UnlockDiagnosticVMOptions) {
|
||||
output()->print_cr("GC.class_stats command requires -XX:+UnlockDiagnosticVMOptions");
|
||||
return;
|
||||
}
|
||||
|
||||
VM_GC_HeapInspection heapop(output(),
|
||||
true, /* request_full_gc */
|
||||
true /* need_prologue */);
|
||||
heapop.set_csv_format(_csv.value());
|
||||
heapop.set_print_help(_help.value());
|
||||
heapop.set_print_class_stats(true);
|
||||
if (_all.value()) {
|
||||
if (_columns.has_value()) {
|
||||
output()->print_cr("Cannot specify -all and individual columns at the same time");
|
||||
return;
|
||||
} else {
|
||||
heapop.set_columns(NULL);
|
||||
}
|
||||
} else {
|
||||
if (_columns.has_value()) {
|
||||
heapop.set_columns(_columns.value());
|
||||
} else {
|
||||
heapop.set_columns(DEFAULT_COLUMNS);
|
||||
}
|
||||
}
|
||||
VMThread::execute(&heapop);
|
||||
}
|
||||
|
||||
int ClassStatsDCmd::num_arguments() {
|
||||
ResourceMark rm;
|
||||
ClassStatsDCmd* dcmd = new ClassStatsDCmd(NULL, false);
|
||||
if (dcmd != NULL) {
|
||||
DCmdMark mark(dcmd);
|
||||
return dcmd->_dcmdparser.num_arguments();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
ThreadDumpDCmd::ThreadDumpDCmd(outputStream* output, bool heap) :
|
||||
DCmdWithParser(output, heap),
|
||||
_locks("-l", "print java.util.concurrent locks", "BOOLEAN", false, "false") {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2013, 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
|
||||
@ -178,7 +178,7 @@ public:
|
||||
};
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
// See also: inspeactheap in attachListener.cpp
|
||||
// See also: inspectheap in attachListener.cpp
|
||||
class ClassHistogramDCmd : public DCmdWithParser {
|
||||
protected:
|
||||
DCmdArgument<bool> _all;
|
||||
@ -197,6 +197,27 @@ public:
|
||||
virtual void execute(TRAPS);
|
||||
};
|
||||
|
||||
class ClassStatsDCmd : public DCmdWithParser {
|
||||
protected:
|
||||
DCmdArgument<bool> _all;
|
||||
DCmdArgument<bool> _csv;
|
||||
DCmdArgument<bool> _help;
|
||||
DCmdArgument<char*> _columns;
|
||||
public:
|
||||
ClassStatsDCmd(outputStream* output, bool heap);
|
||||
static const char* name() {
|
||||
return "GC.class_stats";
|
||||
}
|
||||
static const char* description() {
|
||||
return "Provide statistics about Java class meta data. Requires -XX:+UnlockDiagnosticVMOptions.";
|
||||
}
|
||||
static const char* impact() {
|
||||
return "High: Depends on Java heap size and content.";
|
||||
}
|
||||
static int num_arguments();
|
||||
virtual void execute(TRAPS);
|
||||
};
|
||||
|
||||
// See also: thread_dump in attachListener.cpp
|
||||
class ThreadDumpDCmd : public DCmdWithParser {
|
||||
protected:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user