Wed, 26 Jun 2013 16:58:37 +0200
8013590: NPG: Add a memory pool MXBean for Metaspace
Reviewed-by: jmasa, mgerdin
duke@435 | 1 | /* |
acorn@4497 | 2 | * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. |
duke@435 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
duke@435 | 4 | * |
duke@435 | 5 | * This code is free software; you can redistribute it and/or modify it |
duke@435 | 6 | * under the terms of the GNU General Public License version 2 only, as |
duke@435 | 7 | * published by the Free Software Foundation. |
duke@435 | 8 | * |
duke@435 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
duke@435 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
duke@435 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
duke@435 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
duke@435 | 13 | * accompanied this code). |
duke@435 | 14 | * |
duke@435 | 15 | * You should have received a copy of the GNU General Public License version |
duke@435 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
duke@435 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
duke@435 | 18 | * |
trims@1907 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
trims@1907 | 20 | * or visit www.oracle.com if you need additional information or have any |
trims@1907 | 21 | * questions. |
duke@435 | 22 | * |
duke@435 | 23 | */ |
duke@435 | 24 | |
stefank@2314 | 25 | #include "precompiled.hpp" |
acorn@4497 | 26 | #include "classfile/classLoaderData.hpp" |
stefank@2314 | 27 | #include "gc_interface/collectedHeap.hpp" |
stefank@2314 | 28 | #include "memory/genCollectedHeap.hpp" |
stefank@2314 | 29 | #include "memory/heapInspection.hpp" |
stefank@2314 | 30 | #include "memory/resourceArea.hpp" |
stefank@2314 | 31 | #include "runtime/os.hpp" |
stefank@2314 | 32 | #include "utilities/globalDefinitions.hpp" |
jprovino@4542 | 33 | #include "utilities/macros.hpp" |
jprovino@4542 | 34 | #if INCLUDE_ALL_GCS |
stefank@2314 | 35 | #include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp" |
jprovino@4542 | 36 | #endif // INCLUDE_ALL_GCS |
duke@435 | 37 | |
duke@435 | 38 | // HeapInspection |
duke@435 | 39 | |
duke@435 | 40 | int KlassInfoEntry::compare(KlassInfoEntry* e1, KlassInfoEntry* e2) { |
duke@435 | 41 | if(e1->_instance_words > e2->_instance_words) { |
duke@435 | 42 | return -1; |
duke@435 | 43 | } else if(e1->_instance_words < e2->_instance_words) { |
duke@435 | 44 | return 1; |
duke@435 | 45 | } |
acorn@4497 | 46 | // Sort alphabetically, note 'Z' < '[' < 'a', but it's better to group |
acorn@4497 | 47 | // the array classes before all the instance classes. |
acorn@4497 | 48 | ResourceMark rm; |
acorn@4497 | 49 | const char* name1 = e1->klass()->external_name(); |
acorn@4497 | 50 | const char* name2 = e2->klass()->external_name(); |
acorn@4497 | 51 | bool d1 = (name1[0] == '['); |
acorn@4497 | 52 | bool d2 = (name2[0] == '['); |
acorn@4497 | 53 | if (d1 && !d2) { |
acorn@4497 | 54 | return -1; |
acorn@4497 | 55 | } else if (d2 && !d1) { |
acorn@4497 | 56 | return 1; |
acorn@4497 | 57 | } else { |
acorn@4497 | 58 | return strcmp(name1, name2); |
acorn@4497 | 59 | } |
duke@435 | 60 | } |
duke@435 | 61 | |
acorn@4497 | 62 | const char* KlassInfoEntry::name() const { |
acorn@4497 | 63 | const char* name; |
coleenp@4037 | 64 | if (_klass->name() != NULL) { |
coleenp@4037 | 65 | name = _klass->external_name(); |
duke@435 | 66 | } else { |
duke@435 | 67 | if (_klass == Universe::boolArrayKlassObj()) name = "<boolArrayKlass>"; else |
duke@435 | 68 | if (_klass == Universe::charArrayKlassObj()) name = "<charArrayKlass>"; else |
duke@435 | 69 | if (_klass == Universe::singleArrayKlassObj()) name = "<singleArrayKlass>"; else |
duke@435 | 70 | if (_klass == Universe::doubleArrayKlassObj()) name = "<doubleArrayKlass>"; else |
duke@435 | 71 | if (_klass == Universe::byteArrayKlassObj()) name = "<byteArrayKlass>"; else |
duke@435 | 72 | if (_klass == Universe::shortArrayKlassObj()) name = "<shortArrayKlass>"; else |
duke@435 | 73 | if (_klass == Universe::intArrayKlassObj()) name = "<intArrayKlass>"; else |
duke@435 | 74 | if (_klass == Universe::longArrayKlassObj()) name = "<longArrayKlass>"; else |
duke@435 | 75 | name = "<no name>"; |
duke@435 | 76 | } |
acorn@4497 | 77 | return name; |
acorn@4497 | 78 | } |
acorn@4497 | 79 | |
acorn@4497 | 80 | void KlassInfoEntry::print_on(outputStream* st) const { |
acorn@4497 | 81 | ResourceMark rm; |
acorn@4497 | 82 | |
duke@435 | 83 | // simplify the formatting (ILP32 vs LP64) - always cast the numbers to 64-bit |
ysr@446 | 84 | st->print_cr(INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13) " %s", |
duke@435 | 85 | (jlong) _instance_count, |
duke@435 | 86 | (julong) _instance_words * HeapWordSize, |
acorn@4497 | 87 | name()); |
duke@435 | 88 | } |
duke@435 | 89 | |
coleenp@4037 | 90 | KlassInfoEntry* KlassInfoBucket::lookup(Klass* const k) { |
duke@435 | 91 | KlassInfoEntry* elt = _list; |
duke@435 | 92 | while (elt != NULL) { |
duke@435 | 93 | if (elt->is_equal(k)) { |
duke@435 | 94 | return elt; |
duke@435 | 95 | } |
duke@435 | 96 | elt = elt->next(); |
duke@435 | 97 | } |
sla@5237 | 98 | elt = new (std::nothrow) KlassInfoEntry(k, list()); |
ysr@446 | 99 | // We may be out of space to allocate the new entry. |
ysr@446 | 100 | if (elt != NULL) { |
ysr@446 | 101 | set_list(elt); |
ysr@446 | 102 | } |
duke@435 | 103 | return elt; |
duke@435 | 104 | } |
duke@435 | 105 | |
duke@435 | 106 | void KlassInfoBucket::iterate(KlassInfoClosure* cic) { |
duke@435 | 107 | KlassInfoEntry* elt = _list; |
duke@435 | 108 | while (elt != NULL) { |
duke@435 | 109 | cic->do_cinfo(elt); |
duke@435 | 110 | elt = elt->next(); |
duke@435 | 111 | } |
duke@435 | 112 | } |
duke@435 | 113 | |
duke@435 | 114 | void KlassInfoBucket::empty() { |
duke@435 | 115 | KlassInfoEntry* elt = _list; |
duke@435 | 116 | _list = NULL; |
duke@435 | 117 | while (elt != NULL) { |
duke@435 | 118 | KlassInfoEntry* next = elt->next(); |
duke@435 | 119 | delete elt; |
duke@435 | 120 | elt = next; |
duke@435 | 121 | } |
duke@435 | 122 | } |
duke@435 | 123 | |
acorn@4497 | 124 | void KlassInfoTable::AllClassesFinder::do_klass(Klass* k) { |
acorn@4497 | 125 | // This has the SIDE EFFECT of creating a KlassInfoEntry |
acorn@4497 | 126 | // for <k>, if one doesn't exist yet. |
acorn@4497 | 127 | _table->lookup(k); |
acorn@4497 | 128 | } |
acorn@4497 | 129 | |
sla@5237 | 130 | KlassInfoTable::KlassInfoTable(bool need_class_stats) { |
sla@5237 | 131 | _size_of_instances_in_words = 0; |
ysr@446 | 132 | _size = 0; |
sla@5237 | 133 | _ref = (HeapWord*) Universe::boolArrayKlassObj(); |
sla@5237 | 134 | _buckets = |
sla@5237 | 135 | (KlassInfoBucket*) AllocateHeap(sizeof(KlassInfoBucket) * _num_buckets, |
sla@5237 | 136 | mtInternal, 0, AllocFailStrategy::RETURN_NULL); |
ysr@446 | 137 | if (_buckets != NULL) { |
sla@5237 | 138 | _size = _num_buckets; |
ysr@446 | 139 | for (int index = 0; index < _size; index++) { |
ysr@446 | 140 | _buckets[index].initialize(); |
ysr@446 | 141 | } |
acorn@4497 | 142 | if (need_class_stats) { |
acorn@4497 | 143 | AllClassesFinder finder(this); |
acorn@4497 | 144 | ClassLoaderDataGraph::classes_do(&finder); |
acorn@4497 | 145 | } |
duke@435 | 146 | } |
duke@435 | 147 | } |
duke@435 | 148 | |
duke@435 | 149 | KlassInfoTable::~KlassInfoTable() { |
ysr@446 | 150 | if (_buckets != NULL) { |
ysr@446 | 151 | for (int index = 0; index < _size; index++) { |
ysr@446 | 152 | _buckets[index].empty(); |
ysr@446 | 153 | } |
zgu@3900 | 154 | FREE_C_HEAP_ARRAY(KlassInfoBucket, _buckets, mtInternal); |
ysr@446 | 155 | _size = 0; |
duke@435 | 156 | } |
duke@435 | 157 | } |
duke@435 | 158 | |
minqi@5097 | 159 | uint KlassInfoTable::hash(const Klass* p) { |
coleenp@4037 | 160 | assert(p->is_metadata(), "all klasses are metadata"); |
duke@435 | 161 | return (uint)(((uintptr_t)p - (uintptr_t)_ref) >> 2); |
duke@435 | 162 | } |
duke@435 | 163 | |
minqi@5097 | 164 | KlassInfoEntry* KlassInfoTable::lookup(Klass* k) { |
duke@435 | 165 | uint idx = hash(k) % _size; |
ysr@446 | 166 | assert(_buckets != NULL, "Allocation failure should have been caught"); |
duke@435 | 167 | KlassInfoEntry* e = _buckets[idx].lookup(k); |
ysr@446 | 168 | // Lookup may fail if this is a new klass for which we |
ysr@446 | 169 | // could not allocate space for an new entry. |
ysr@446 | 170 | assert(e == NULL || k == e->klass(), "must be equal"); |
duke@435 | 171 | return e; |
duke@435 | 172 | } |
duke@435 | 173 | |
ysr@446 | 174 | // Return false if the entry could not be recorded on account |
ysr@446 | 175 | // of running out of space required to create a new entry. |
ysr@446 | 176 | bool KlassInfoTable::record_instance(const oop obj) { |
coleenp@4037 | 177 | Klass* k = obj->klass(); |
duke@435 | 178 | KlassInfoEntry* elt = lookup(k); |
ysr@446 | 179 | // elt may be NULL if it's a new klass for which we |
ysr@446 | 180 | // could not allocate space for a new entry in the hashtable. |
ysr@446 | 181 | if (elt != NULL) { |
ysr@446 | 182 | elt->set_count(elt->count() + 1); |
ysr@446 | 183 | elt->set_words(elt->words() + obj->size()); |
sla@5237 | 184 | _size_of_instances_in_words += obj->size(); |
ysr@446 | 185 | return true; |
ysr@446 | 186 | } else { |
ysr@446 | 187 | return false; |
ysr@446 | 188 | } |
duke@435 | 189 | } |
duke@435 | 190 | |
duke@435 | 191 | void KlassInfoTable::iterate(KlassInfoClosure* cic) { |
ysr@446 | 192 | assert(_size == 0 || _buckets != NULL, "Allocation failure should have been caught"); |
duke@435 | 193 | for (int index = 0; index < _size; index++) { |
duke@435 | 194 | _buckets[index].iterate(cic); |
duke@435 | 195 | } |
duke@435 | 196 | } |
duke@435 | 197 | |
sla@5237 | 198 | size_t KlassInfoTable::size_of_instances_in_words() const { |
sla@5237 | 199 | return _size_of_instances_in_words; |
sla@5237 | 200 | } |
sla@5237 | 201 | |
duke@435 | 202 | int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) { |
duke@435 | 203 | return (*e1)->compare(*e1,*e2); |
duke@435 | 204 | } |
duke@435 | 205 | |
sla@5237 | 206 | KlassInfoHisto::KlassInfoHisto(KlassInfoTable* cit, const char* title) : |
acorn@4497 | 207 | _cit(cit), |
duke@435 | 208 | _title(title) { |
sla@5237 | 209 | _elements = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<KlassInfoEntry*>(_histo_initial_size, true); |
duke@435 | 210 | } |
duke@435 | 211 | |
duke@435 | 212 | KlassInfoHisto::~KlassInfoHisto() { |
duke@435 | 213 | delete _elements; |
duke@435 | 214 | } |
duke@435 | 215 | |
duke@435 | 216 | void KlassInfoHisto::add(KlassInfoEntry* cie) { |
duke@435 | 217 | elements()->append(cie); |
duke@435 | 218 | } |
duke@435 | 219 | |
duke@435 | 220 | void KlassInfoHisto::sort() { |
duke@435 | 221 | elements()->sort(KlassInfoHisto::sort_helper); |
duke@435 | 222 | } |
duke@435 | 223 | |
duke@435 | 224 | void KlassInfoHisto::print_elements(outputStream* st) const { |
duke@435 | 225 | // simplify the formatting (ILP32 vs LP64) - store the sum in 64-bit |
duke@435 | 226 | jlong total = 0; |
duke@435 | 227 | julong totalw = 0; |
duke@435 | 228 | for(int i=0; i < elements()->length(); i++) { |
duke@435 | 229 | st->print("%4d: ", i+1); |
duke@435 | 230 | elements()->at(i)->print_on(st); |
duke@435 | 231 | total += elements()->at(i)->count(); |
duke@435 | 232 | totalw += elements()->at(i)->words(); |
duke@435 | 233 | } |
ysr@446 | 234 | st->print_cr("Total " INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13), |
duke@435 | 235 | total, totalw * HeapWordSize); |
duke@435 | 236 | } |
duke@435 | 237 | |
acorn@4497 | 238 | #define MAKE_COL_NAME(field, name, help) #name, |
acorn@4497 | 239 | #define MAKE_COL_HELP(field, name, help) help, |
acorn@4497 | 240 | |
acorn@4497 | 241 | static const char *name_table[] = { |
acorn@4497 | 242 | HEAP_INSPECTION_COLUMNS_DO(MAKE_COL_NAME) |
acorn@4497 | 243 | }; |
acorn@4497 | 244 | |
acorn@4497 | 245 | static const char *help_table[] = { |
acorn@4497 | 246 | HEAP_INSPECTION_COLUMNS_DO(MAKE_COL_HELP) |
acorn@4497 | 247 | }; |
acorn@4497 | 248 | |
acorn@4497 | 249 | bool KlassInfoHisto::is_selected(const char *col_name) { |
acorn@4497 | 250 | if (_selected_columns == NULL) { |
acorn@4497 | 251 | return true; |
acorn@4497 | 252 | } |
acorn@4497 | 253 | if (strcmp(_selected_columns, col_name) == 0) { |
acorn@4497 | 254 | return true; |
acorn@4497 | 255 | } |
acorn@4497 | 256 | |
acorn@4497 | 257 | const char *start = strstr(_selected_columns, col_name); |
acorn@4497 | 258 | if (start == NULL) { |
acorn@4497 | 259 | return false; |
acorn@4497 | 260 | } |
acorn@4497 | 261 | |
acorn@4497 | 262 | // The following must be true, because _selected_columns != col_name |
acorn@4497 | 263 | if (start > _selected_columns && start[-1] != ',') { |
acorn@4497 | 264 | return false; |
acorn@4497 | 265 | } |
acorn@4497 | 266 | char x = start[strlen(col_name)]; |
acorn@4497 | 267 | if (x != ',' && x != '\0') { |
acorn@4497 | 268 | return false; |
acorn@4497 | 269 | } |
acorn@4497 | 270 | |
acorn@4497 | 271 | return true; |
acorn@4497 | 272 | } |
acorn@4497 | 273 | |
acorn@4497 | 274 | void KlassInfoHisto::print_title(outputStream* st, bool csv_format, |
acorn@4497 | 275 | bool selected[], int width_table[], |
acorn@4497 | 276 | const char *name_table[]) { |
acorn@4497 | 277 | if (csv_format) { |
acorn@4497 | 278 | st->print("Index,Super"); |
acorn@4497 | 279 | for (int c=0; c<KlassSizeStats::_num_columns; c++) { |
acorn@4497 | 280 | if (selected[c]) {st->print(",%s", name_table[c]);} |
acorn@4497 | 281 | } |
acorn@4497 | 282 | st->print(",ClassName"); |
acorn@4497 | 283 | } else { |
acorn@4497 | 284 | st->print("Index Super"); |
acorn@4497 | 285 | for (int c=0; c<KlassSizeStats::_num_columns; c++) { |
acorn@4497 | 286 | if (selected[c]) {st->print(str_fmt(width_table[c]), name_table[c]);} |
acorn@4497 | 287 | } |
acorn@4497 | 288 | st->print(" ClassName"); |
acorn@4497 | 289 | } |
acorn@4497 | 290 | |
acorn@4497 | 291 | if (is_selected("ClassLoader")) { |
acorn@4497 | 292 | st->print(",ClassLoader"); |
acorn@4497 | 293 | } |
acorn@4497 | 294 | st->cr(); |
acorn@4497 | 295 | } |
acorn@4497 | 296 | |
acorn@4497 | 297 | void KlassInfoHisto::print_class_stats(outputStream* st, |
acorn@4497 | 298 | bool csv_format, const char *columns) { |
acorn@4497 | 299 | ResourceMark rm; |
acorn@4497 | 300 | KlassSizeStats sz, sz_sum; |
acorn@4497 | 301 | int i; |
acorn@4497 | 302 | julong *col_table = (julong*)(&sz); |
acorn@4497 | 303 | julong *colsum_table = (julong*)(&sz_sum); |
acorn@4497 | 304 | int width_table[KlassSizeStats::_num_columns]; |
acorn@4497 | 305 | bool selected[KlassSizeStats::_num_columns]; |
acorn@4497 | 306 | |
acorn@4497 | 307 | _selected_columns = columns; |
acorn@4497 | 308 | |
acorn@4497 | 309 | memset(&sz_sum, 0, sizeof(sz_sum)); |
acorn@4497 | 310 | for (int c=0; c<KlassSizeStats::_num_columns; c++) { |
acorn@4497 | 311 | selected[c] = is_selected(name_table[c]); |
acorn@4497 | 312 | } |
acorn@4497 | 313 | |
acorn@4497 | 314 | for(i=0; i < elements()->length(); i++) { |
acorn@4497 | 315 | elements()->at(i)->set_index(i+1); |
acorn@4497 | 316 | } |
acorn@4497 | 317 | |
acorn@4497 | 318 | for (int pass=1; pass<=2; pass++) { |
acorn@4497 | 319 | if (pass == 2) { |
acorn@4497 | 320 | print_title(st, csv_format, selected, width_table, name_table); |
acorn@4497 | 321 | } |
acorn@4497 | 322 | for(i=0; i < elements()->length(); i++) { |
acorn@4497 | 323 | KlassInfoEntry* e = (KlassInfoEntry*)elements()->at(i); |
acorn@4497 | 324 | const Klass* k = e->klass(); |
acorn@4497 | 325 | |
acorn@4497 | 326 | memset(&sz, 0, sizeof(sz)); |
acorn@4497 | 327 | sz._inst_count = e->count(); |
acorn@4497 | 328 | sz._inst_bytes = HeapWordSize * e->words(); |
acorn@4497 | 329 | k->collect_statistics(&sz); |
acorn@4497 | 330 | sz._total_bytes = sz._ro_bytes + sz._rw_bytes; |
acorn@4497 | 331 | |
acorn@4497 | 332 | if (pass == 1) { |
acorn@4497 | 333 | for (int c=0; c<KlassSizeStats::_num_columns; c++) { |
acorn@4497 | 334 | colsum_table[c] += col_table[c]; |
acorn@4497 | 335 | } |
acorn@4497 | 336 | } else { |
acorn@4497 | 337 | int super_index = -1; |
acorn@4497 | 338 | if (k->oop_is_instance()) { |
acorn@4497 | 339 | Klass* super = ((InstanceKlass*)k)->java_super(); |
acorn@4497 | 340 | if (super) { |
acorn@4497 | 341 | KlassInfoEntry* super_e = _cit->lookup(super); |
acorn@4497 | 342 | if (super_e) { |
acorn@4497 | 343 | super_index = super_e->index(); |
acorn@4497 | 344 | } |
acorn@4497 | 345 | } |
acorn@4497 | 346 | } |
acorn@4497 | 347 | |
acorn@4497 | 348 | if (csv_format) { |
acorn@4497 | 349 | st->print("%d,%d", e->index(), super_index); |
acorn@4497 | 350 | for (int c=0; c<KlassSizeStats::_num_columns; c++) { |
acorn@4497 | 351 | if (selected[c]) {st->print("," JULONG_FORMAT, col_table[c]);} |
acorn@4497 | 352 | } |
acorn@4497 | 353 | st->print(",%s",e->name()); |
acorn@4497 | 354 | } else { |
acorn@4497 | 355 | st->print("%5d %5d", e->index(), super_index); |
acorn@4497 | 356 | for (int c=0; c<KlassSizeStats::_num_columns; c++) { |
acorn@4497 | 357 | if (selected[c]) {print_julong(st, width_table[c], col_table[c]);} |
acorn@4497 | 358 | } |
acorn@4497 | 359 | st->print(" %s", e->name()); |
acorn@4497 | 360 | } |
acorn@4497 | 361 | if (is_selected("ClassLoader")) { |
acorn@4497 | 362 | ClassLoaderData* loader_data = k->class_loader_data(); |
acorn@4497 | 363 | st->print(","); |
acorn@4497 | 364 | loader_data->print_value_on(st); |
acorn@4497 | 365 | } |
acorn@4497 | 366 | st->cr(); |
acorn@4497 | 367 | } |
acorn@4497 | 368 | } |
acorn@4497 | 369 | |
acorn@4497 | 370 | if (pass == 1) { |
acorn@4497 | 371 | for (int c=0; c<KlassSizeStats::_num_columns; c++) { |
acorn@4497 | 372 | width_table[c] = col_width(colsum_table[c], name_table[c]); |
acorn@4497 | 373 | } |
acorn@4497 | 374 | } |
acorn@4497 | 375 | } |
acorn@4497 | 376 | |
acorn@4497 | 377 | sz_sum._inst_size = 0; |
acorn@4497 | 378 | |
acorn@4497 | 379 | if (csv_format) { |
acorn@4497 | 380 | st->print(","); |
acorn@4497 | 381 | for (int c=0; c<KlassSizeStats::_num_columns; c++) { |
acorn@4497 | 382 | if (selected[c]) {st->print("," JULONG_FORMAT, colsum_table[c]);} |
acorn@4497 | 383 | } |
acorn@4497 | 384 | } else { |
acorn@4497 | 385 | st->print(" "); |
acorn@4497 | 386 | for (int c=0; c<KlassSizeStats::_num_columns; c++) { |
acorn@4497 | 387 | if (selected[c]) {print_julong(st, width_table[c], colsum_table[c]);} |
acorn@4497 | 388 | } |
acorn@4497 | 389 | st->print(" Total"); |
acorn@4497 | 390 | if (sz_sum._total_bytes > 0) { |
acorn@4497 | 391 | st->cr(); |
acorn@4497 | 392 | st->print(" "); |
acorn@4497 | 393 | for (int c=0; c<KlassSizeStats::_num_columns; c++) { |
acorn@4497 | 394 | if (selected[c]) { |
acorn@4497 | 395 | switch (c) { |
acorn@4497 | 396 | case KlassSizeStats::_index_inst_size: |
acorn@4497 | 397 | case KlassSizeStats::_index_inst_count: |
acorn@4497 | 398 | case KlassSizeStats::_index_method_count: |
acorn@4497 | 399 | st->print(str_fmt(width_table[c]), "-"); |
acorn@4497 | 400 | break; |
acorn@4497 | 401 | default: |
acorn@4497 | 402 | { |
acorn@4497 | 403 | double perc = (double)(100) * (double)(colsum_table[c]) / (double)sz_sum._total_bytes; |
acorn@4497 | 404 | st->print(perc_fmt(width_table[c]), perc); |
acorn@4497 | 405 | } |
acorn@4497 | 406 | } |
acorn@4497 | 407 | } |
acorn@4497 | 408 | } |
acorn@4497 | 409 | } |
acorn@4497 | 410 | } |
acorn@4497 | 411 | st->cr(); |
acorn@4497 | 412 | |
acorn@4497 | 413 | if (!csv_format) { |
acorn@4497 | 414 | print_title(st, csv_format, selected, width_table, name_table); |
acorn@4497 | 415 | } |
acorn@4497 | 416 | } |
acorn@4497 | 417 | |
acorn@4497 | 418 | julong KlassInfoHisto::annotations_bytes(Array<AnnotationArray*>* p) const { |
acorn@4497 | 419 | julong bytes = 0; |
acorn@4497 | 420 | if (p != NULL) { |
acorn@4497 | 421 | for (int i = 0; i < p->length(); i++) { |
acorn@4497 | 422 | bytes += count_bytes_array(p->at(i)); |
acorn@4497 | 423 | } |
acorn@4497 | 424 | bytes += count_bytes_array(p); |
acorn@4497 | 425 | } |
acorn@4497 | 426 | return bytes; |
acorn@4497 | 427 | } |
acorn@4497 | 428 | |
acorn@4497 | 429 | void KlassInfoHisto::print_histo_on(outputStream* st, bool print_stats, |
acorn@4497 | 430 | bool csv_format, const char *columns) { |
acorn@4497 | 431 | if (print_stats) { |
acorn@4497 | 432 | print_class_stats(st, csv_format, columns); |
acorn@4497 | 433 | } else { |
acorn@4497 | 434 | st->print_cr("%s",title()); |
acorn@4497 | 435 | print_elements(st); |
acorn@4497 | 436 | } |
duke@435 | 437 | } |
duke@435 | 438 | |
duke@435 | 439 | class HistoClosure : public KlassInfoClosure { |
duke@435 | 440 | private: |
duke@435 | 441 | KlassInfoHisto* _cih; |
duke@435 | 442 | public: |
duke@435 | 443 | HistoClosure(KlassInfoHisto* cih) : _cih(cih) {} |
duke@435 | 444 | |
duke@435 | 445 | void do_cinfo(KlassInfoEntry* cie) { |
duke@435 | 446 | _cih->add(cie); |
duke@435 | 447 | } |
duke@435 | 448 | }; |
duke@435 | 449 | |
duke@435 | 450 | class RecordInstanceClosure : public ObjectClosure { |
duke@435 | 451 | private: |
duke@435 | 452 | KlassInfoTable* _cit; |
ysr@446 | 453 | size_t _missed_count; |
sla@5237 | 454 | BoolObjectClosure* _filter; |
duke@435 | 455 | public: |
sla@5237 | 456 | RecordInstanceClosure(KlassInfoTable* cit, BoolObjectClosure* filter) : |
sla@5237 | 457 | _cit(cit), _missed_count(0), _filter(filter) {} |
duke@435 | 458 | |
duke@435 | 459 | void do_object(oop obj) { |
sla@5237 | 460 | if (should_visit(obj)) { |
sla@5237 | 461 | if (!_cit->record_instance(obj)) { |
sla@5237 | 462 | _missed_count++; |
sla@5237 | 463 | } |
ysr@446 | 464 | } |
duke@435 | 465 | } |
ysr@446 | 466 | |
ysr@446 | 467 | size_t missed_count() { return _missed_count; } |
sla@5237 | 468 | |
sla@5237 | 469 | private: |
sla@5237 | 470 | bool should_visit(oop obj) { |
sla@5237 | 471 | return _filter == NULL || _filter->do_object_b(obj); |
sla@5237 | 472 | } |
duke@435 | 473 | }; |
duke@435 | 474 | |
sla@5237 | 475 | size_t HeapInspection::populate_table(KlassInfoTable* cit, BoolObjectClosure *filter) { |
duke@435 | 476 | ResourceMark rm; |
sla@5237 | 477 | |
sla@5237 | 478 | RecordInstanceClosure ric(cit, filter); |
sla@5237 | 479 | Universe::heap()->object_iterate(&ric); |
sla@5237 | 480 | return ric.missed_count(); |
sla@5237 | 481 | } |
sla@5237 | 482 | |
sla@5237 | 483 | void HeapInspection::heap_inspection(outputStream* st) { |
sla@5237 | 484 | ResourceMark rm; |
coleenp@4037 | 485 | |
acorn@4497 | 486 | if (_print_help) { |
acorn@4497 | 487 | for (int c=0; c<KlassSizeStats::_num_columns; c++) { |
acorn@4497 | 488 | st->print("%s:\n\t", name_table[c]); |
acorn@4497 | 489 | const int max_col = 60; |
acorn@4497 | 490 | int col = 0; |
acorn@4497 | 491 | for (const char *p = help_table[c]; *p; p++,col++) { |
acorn@4497 | 492 | if (col >= max_col && *p == ' ') { |
acorn@4497 | 493 | st->print("\n\t"); |
acorn@4497 | 494 | col = 0; |
acorn@4497 | 495 | } else { |
acorn@4497 | 496 | st->print("%c", *p); |
acorn@4497 | 497 | } |
acorn@4497 | 498 | } |
acorn@4497 | 499 | st->print_cr(".\n"); |
acorn@4497 | 500 | } |
acorn@4497 | 501 | return; |
acorn@4497 | 502 | } |
acorn@4497 | 503 | |
sla@5237 | 504 | KlassInfoTable cit(_print_class_stats); |
ysr@446 | 505 | if (!cit.allocation_failed()) { |
sla@5237 | 506 | size_t missed_count = populate_table(&cit); |
ysr@446 | 507 | if (missed_count != 0) { |
ysr@446 | 508 | st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT |
ysr@446 | 509 | " total instances in data below", |
ysr@446 | 510 | missed_count); |
ysr@446 | 511 | } |
sla@5237 | 512 | |
ysr@446 | 513 | // Sort and print klass instance info |
acorn@4497 | 514 | const char *title = "\n" |
acorn@4497 | 515 | " num #instances #bytes class name\n" |
acorn@4497 | 516 | "----------------------------------------------"; |
sla@5237 | 517 | KlassInfoHisto histo(&cit, title); |
ysr@446 | 518 | HistoClosure hc(&histo); |
sla@5237 | 519 | |
ysr@446 | 520 | cit.iterate(&hc); |
sla@5237 | 521 | |
ysr@446 | 522 | histo.sort(); |
acorn@4497 | 523 | histo.print_histo_on(st, _print_class_stats, _csv_format, _columns); |
ysr@446 | 524 | } else { |
ysr@446 | 525 | st->print_cr("WARNING: Ran out of C-heap; histogram not generated"); |
ysr@446 | 526 | } |
duke@435 | 527 | st->flush(); |
duke@435 | 528 | } |
duke@435 | 529 | |
duke@435 | 530 | class FindInstanceClosure : public ObjectClosure { |
duke@435 | 531 | private: |
coleenp@4037 | 532 | Klass* _klass; |
duke@435 | 533 | GrowableArray<oop>* _result; |
duke@435 | 534 | |
duke@435 | 535 | public: |
coleenp@4037 | 536 | FindInstanceClosure(Klass* k, GrowableArray<oop>* result) : _klass(k), _result(result) {}; |
duke@435 | 537 | |
duke@435 | 538 | void do_object(oop obj) { |
duke@435 | 539 | if (obj->is_a(_klass)) { |
duke@435 | 540 | _result->append(obj); |
duke@435 | 541 | } |
duke@435 | 542 | } |
duke@435 | 543 | }; |
duke@435 | 544 | |
coleenp@4037 | 545 | void HeapInspection::find_instances_at_safepoint(Klass* k, GrowableArray<oop>* result) { |
duke@435 | 546 | assert(SafepointSynchronize::is_at_safepoint(), "all threads are stopped"); |
jcoomes@1844 | 547 | assert(Heap_lock->is_locked(), "should have the Heap_lock"); |
duke@435 | 548 | |
duke@435 | 549 | // Ensure that the heap is parsable |
duke@435 | 550 | Universe::heap()->ensure_parsability(false); // no need to retire TALBs |
duke@435 | 551 | |
duke@435 | 552 | // Iterate over objects in the heap |
duke@435 | 553 | FindInstanceClosure fic(k, result); |
jmasa@952 | 554 | // If this operation encounters a bad object when using CMS, |
coleenp@4037 | 555 | // consider using safe_object_iterate() which avoids metadata |
jmasa@952 | 556 | // objects that may contain bad references. |
duke@435 | 557 | Universe::heap()->object_iterate(&fic); |
duke@435 | 558 | } |