diff -r 000000000000 -r a61af66fc99e src/share/vm/memory/heapInspection.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/memory/heapInspection.cpp Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,281 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +# include "incls/_precompiled.incl" +# include "incls/_heapInspection.cpp.incl" + +// HeapInspection + +int KlassInfoEntry::compare(KlassInfoEntry* e1, KlassInfoEntry* e2) { + if(e1->_instance_words > e2->_instance_words) { + return -1; + } else if(e1->_instance_words < e2->_instance_words) { + return 1; + } + return 0; +} + +void KlassInfoEntry::print_on(outputStream* st) const { + ResourceMark rm; + const char* name;; + if (_klass->klass_part()->name() != NULL) { + name = _klass->klass_part()->external_name(); + } else { + if (_klass == Universe::klassKlassObj()) name = ""; else + if (_klass == Universe::arrayKlassKlassObj()) name = ""; else + if (_klass == Universe::objArrayKlassKlassObj()) name = ""; else + if (_klass == Universe::instanceKlassKlassObj()) name = ""; else + if (_klass == Universe::typeArrayKlassKlassObj()) name = ""; else + if (_klass == Universe::symbolKlassObj()) name = ""; else + if (_klass == Universe::boolArrayKlassObj()) name = ""; else + if (_klass == Universe::charArrayKlassObj()) name = ""; else + if (_klass == Universe::singleArrayKlassObj()) name = ""; else + if (_klass == Universe::doubleArrayKlassObj()) name = ""; else + if (_klass == Universe::byteArrayKlassObj()) name = ""; else + if (_klass == Universe::shortArrayKlassObj()) name = ""; else + if (_klass == Universe::intArrayKlassObj()) name = ""; else + if (_klass == Universe::longArrayKlassObj()) name = ""; else + if (_klass == Universe::methodKlassObj()) name = ""; else + if (_klass == Universe::constMethodKlassObj()) name = ""; else + if (_klass == Universe::methodDataKlassObj()) name = ""; else + if (_klass == Universe::constantPoolKlassObj()) name = ""; else + if (_klass == Universe::constantPoolCacheKlassObj()) name = ""; else + if (_klass == Universe::compiledICHolderKlassObj()) name = ""; else + 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); +} + +KlassInfoEntry* KlassInfoBucket::lookup(const klassOop k) { + KlassInfoEntry* elt = _list; + while (elt != NULL) { + if (elt->is_equal(k)) { + return elt; + } + elt = elt->next(); + } + elt = new KlassInfoEntry(k, list()); + set_list(elt); + return elt; +} + +void KlassInfoBucket::iterate(KlassInfoClosure* cic) { + KlassInfoEntry* elt = _list; + while (elt != NULL) { + cic->do_cinfo(elt); + elt = elt->next(); + } +} + +void KlassInfoBucket::empty() { + KlassInfoEntry* elt = _list; + _list = NULL; + while (elt != NULL) { + KlassInfoEntry* next = elt->next(); + delete elt; + 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); + } +} + +int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) { + return (*e1)->compare(*e1,*e2); +} + +KlassInfoHisto::KlassInfoHisto(const char* title, int estimatedCount) : + _title(title) { + _elements = new (ResourceObj::C_HEAP) GrowableArray(estimatedCount,true); +} + +KlassInfoHisto::~KlassInfoHisto() { + delete _elements; +} + +void KlassInfoHisto::add(KlassInfoEntry* cie) { + elements()->append(cie); +} + +void KlassInfoHisto::sort() { + elements()->sort(KlassInfoHisto::sort_helper); +} + +void KlassInfoHisto::print_elements(outputStream* st) const { + // simplify the formatting (ILP32 vs LP64) - store the sum in 64-bit + jlong total = 0; + julong totalw = 0; + for(int i=0; i < elements()->length(); i++) { + 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()); + print_elements(st); +} + +class HistoClosure : public KlassInfoClosure { + private: + KlassInfoHisto* _cih; + public: + HistoClosure(KlassInfoHisto* cih) : _cih(cih) {} + + void do_cinfo(KlassInfoEntry* cie) { + _cih->add(cie); + } +}; + +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; + ref = psh->perm_gen()->object_space()->used_region().start(); + break; + } +#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: + klassOop _klass; + GrowableArray* _result; + + public: + FindInstanceClosure(klassOop k, GrowableArray* result) : _klass(k), _result(result) {}; + + void do_object(oop obj) { + if (obj->is_a(_klass)) { + _result->append(obj); + } + } +}; + +void HeapInspection::find_instances_at_safepoint(klassOop k, GrowableArray* result) { + assert(SafepointSynchronize::is_at_safepoint(), "all threads are stopped"); + assert(Heap_lock->is_locked(), "should have the Heap_lock") + + // Ensure that the heap is parsable + Universe::heap()->ensure_parsability(false); // no need to retire TALBs + + // Iterate over objects in the heap + FindInstanceClosure fic(k, result); + Universe::heap()->object_iterate(&fic); +}