hotspot/src/share/vm/memory/heapInspection.cpp

Print this page
rev 611 : Merge

*** 1,10 **** #ifdef USE_PRAGMA_IDENT_SRC #pragma ident "@(#)heapInspection.cpp 1.21 07/05/29 09:44:16 JVM" #endif /* ! * Copyright 2002-2007 Sun Microsystems, Inc. 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. --- 1,10 ---- #ifdef USE_PRAGMA_IDENT_SRC #pragma ident "@(#)heapInspection.cpp 1.21 07/05/29 09:44:16 JVM" #endif /* ! * Copyright 2002-2008 Sun Microsystems, Inc. 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.
*** 66,76 **** if (_klass == Universe::constantPoolCacheKlassObj()) name = "<constantPoolCacheKlass>"; else if (_klass == Universe::compiledICHolderKlassObj()) name = "<compiledICHolderKlass>"; else name = "<no name>"; } // simplify the formatting (ILP32 vs LP64) - always cast the numbers to 64-bit ! st->print_cr("%13" FORMAT64_MODIFIER "d %13" FORMAT64_MODIFIER "u %s", (jlong) _instance_count, (julong) _instance_words * HeapWordSize, name); } --- 66,76 ---- if (_klass == Universe::constantPoolCacheKlassObj()) name = "<constantPoolCacheKlass>"; else if (_klass == Universe::compiledICHolderKlassObj()) name = "<compiledICHolderKlass>"; else name = "<no name>"; } // 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); }
*** 81,91 **** --- 81,94 ---- return elt; } elt = elt->next(); } elt = new KlassInfoEntry(k, list()); + // We may be out of space to allocate the new entry. + if (elt != NULL) { set_list(elt); + } return elt; } void KlassInfoBucket::iterate(KlassInfoClosure* cic) { KlassInfoEntry* elt = _list;
*** 104,150 **** elt = next; } } KlassInfoTable::KlassInfoTable(int size, HeapWord* ref) { ! _size = size; _ref = ref; ! _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, _size); ! for (int index = 0; index < _size; index++) { _buckets[index].initialize(); } } KlassInfoTable::~KlassInfoTable() { for (int index = 0; index < _size; index++) { _buckets[index].empty(); } FREE_C_HEAP_ARRAY(KlassInfoBucket, _buckets); _size = 0; } uint KlassInfoTable::hash(klassOop p) { assert(Universe::heap()->is_in_permanent((HeapWord*)p), "all klasses in permgen"); return (uint)(((uintptr_t)p - (uintptr_t)_ref) >> 2); } KlassInfoEntry* KlassInfoTable::lookup(const klassOop k) { uint idx = hash(k) % _size; KlassInfoEntry* e = _buckets[idx].lookup(k); ! assert(k == e->klass(), "must be equal"); return e; } ! void KlassInfoTable::record_instance(const oop obj) { klassOop k = obj->klass(); KlassInfoEntry* elt = lookup(k); elt->set_count(elt->count() + 1); elt->set_words(elt->words() + obj->size()); } void KlassInfoTable::iterate(KlassInfoClosure* cic) { for (int index = 0; index < _size; index++) { _buckets[index].iterate(cic); } } --- 107,170 ---- elt = next; } } KlassInfoTable::KlassInfoTable(int size, HeapWord* ref) { ! _size = 0; _ref = ref; ! _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, size); ! if (_buckets != NULL) { ! _size = size; for (int index = 0; index < _size; index++) { _buckets[index].initialize(); } + } } KlassInfoTable::~KlassInfoTable() { + if (_buckets != NULL) { for (int index = 0; index < _size; index++) { _buckets[index].empty(); } FREE_C_HEAP_ARRAY(KlassInfoBucket, _buckets); _size = 0; + } } uint KlassInfoTable::hash(klassOop p) { assert(Universe::heap()->is_in_permanent((HeapWord*)p), "all klasses in permgen"); return (uint)(((uintptr_t)p - (uintptr_t)_ref) >> 2); } KlassInfoEntry* KlassInfoTable::lookup(const klassOop k) { uint idx = hash(k) % _size; + assert(_buckets != NULL, "Allocation failure should have been caught"); KlassInfoEntry* e = _buckets[idx].lookup(k); ! // Lookup may fail if this is a new klass for which we ! // could not allocate space for an new entry. ! assert(e == NULL || k == e->klass(), "must be equal"); return e; } ! // Return false if the entry could not be recorded on account ! // of running out of space required to create a new entry. ! bool KlassInfoTable::record_instance(const oop obj) { klassOop k = obj->klass(); KlassInfoEntry* elt = lookup(k); + // elt may be NULL if it's a new klass for which we + // could not allocate space for a new entry in the hashtable. + if (elt != NULL) { elt->set_count(elt->count() + 1); elt->set_words(elt->words() + obj->size()); + return true; + } else { + return false; + } } void KlassInfoTable::iterate(KlassInfoClosure* cic) { + assert(_size == 0 || _buckets != NULL, "Allocation failure should have been caught"); for (int index = 0; index < _size; index++) { _buckets[index].iterate(cic); } }
*** 177,187 **** st->print("%4d: ", i+1); elements()->at(i)->print_on(st); total += elements()->at(i)->count(); totalw += elements()->at(i)->words(); } ! st->print_cr("Total %13" FORMAT64_MODIFIER "d %13" FORMAT64_MODIFIER "u", total, totalw * HeapWordSize); } void KlassInfoHisto::print_on(outputStream* st) const { st->print_cr("%s",title()); --- 197,207 ---- st->print("%4d: ", i+1); elements()->at(i)->print_on(st); total += elements()->at(i)->count(); totalw += elements()->at(i)->words(); } ! st->print_cr("Total " INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13), total, totalw * HeapWordSize); } void KlassInfoHisto::print_on(outputStream* st) const { st->print_cr("%s",title());
*** 200,227 **** }; class RecordInstanceClosure : public ObjectClosure { private: KlassInfoTable* _cit; public: ! RecordInstanceClosure(KlassInfoTable* cit) : _cit(cit) {} void do_object(oop obj) { ! _cit->record_instance(obj); } }; void HeapInspection::heap_inspection(outputStream* st) { ResourceMark rm; HeapWord* ref; CollectedHeap* heap = Universe::heap(); switch (heap->kind()) { case CollectedHeap::GenCollectedHeap: { ! GenCollectedHeap* gch = (GenCollectedHeap*)heap; ! gch->gc_prologue(false /* !full */); // get any necessary locks ! ref = gch->perm_gen()->used_region().start(); break; } #ifndef SERIALGC case CollectedHeap::ParallelScavengeHeap: { ParallelScavengeHeap* psh = (ParallelScavengeHeap*)heap; --- 220,256 ---- }; class RecordInstanceClosure : public ObjectClosure { private: KlassInfoTable* _cit; + size_t _missed_count; public: ! RecordInstanceClosure(KlassInfoTable* cit) : ! _cit(cit), _missed_count(0) {} void do_object(oop obj) { ! if (!_cit->record_instance(obj)) { ! _missed_count++; } + } + + size_t missed_count() { return _missed_count; } }; void HeapInspection::heap_inspection(outputStream* st) { ResourceMark rm; HeapWord* ref; CollectedHeap* heap = Universe::heap(); + bool is_shared_heap = false; switch (heap->kind()) { + case CollectedHeap::G1CollectedHeap: case CollectedHeap::GenCollectedHeap: { ! is_shared_heap = true; ! SharedHeap* sh = (SharedHeap*)heap; ! sh->gc_prologue(false /* !full */); // get any necessary locks, etc. ! ref = sh->perm_gen()->used_region().start(); break; } #ifndef SERIALGC case CollectedHeap::ParallelScavengeHeap: { ParallelScavengeHeap* psh = (ParallelScavengeHeap*)heap;
*** 231,260 **** #endif // SERIALGC default: ShouldNotReachHere(); // Unexpected heap kind for this op } // Collect klass instance info - - // Iterate over objects in the heap KlassInfoTable cit(KlassInfoTable::cit_size, ref); RecordInstanceClosure ric(&cit); Universe::heap()->object_iterate(&ric); // Sort and print klass instance info KlassInfoHisto histo("\n" " num #instances #bytes class name\n" "----------------------------------------------", KlassInfoHisto::histo_initial_size); HistoClosure hc(&histo); cit.iterate(&hc); histo.sort(); histo.print_on(st); st->flush(); ! if (Universe::heap()->kind() == CollectedHeap::GenCollectedHeap) { ! GenCollectedHeap* gch = GenCollectedHeap::heap(); ! gch->gc_epilogue(false /* !full */); // release all acquired locks } } class FindInstanceClosure : public ObjectClosure { private: --- 260,300 ---- #endif // SERIALGC default: ShouldNotReachHere(); // Unexpected heap kind for this op } // Collect klass instance info KlassInfoTable cit(KlassInfoTable::cit_size, ref); + if (!cit.allocation_failed()) { + // Iterate over objects in the heap RecordInstanceClosure ric(&cit); Universe::heap()->object_iterate(&ric); + // Report if certain classes are not counted because of + // running out of C-heap for the histogram. + size_t missed_count = ric.missed_count(); + if (missed_count != 0) { + st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT + " total instances in data below", + missed_count); + } // Sort and print klass instance info KlassInfoHisto histo("\n" " num #instances #bytes class name\n" "----------------------------------------------", KlassInfoHisto::histo_initial_size); HistoClosure hc(&histo); cit.iterate(&hc); histo.sort(); histo.print_on(st); + } else { + st->print_cr("WARNING: Ran out of C-heap; histogram not generated"); + } st->flush(); ! if (is_shared_heap) { ! SharedHeap* sh = (SharedHeap*)heap; ! sh->gc_epilogue(false /* !full */); // release all acquired locks, etc. } } class FindInstanceClosure : public ObjectClosure { private: