duke@435: /* xdono@1014: * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: # include "incls/_precompiled.incl" duke@435: # include "incls/_heapInspection.cpp.incl" duke@435: duke@435: // HeapInspection duke@435: duke@435: int KlassInfoEntry::compare(KlassInfoEntry* e1, KlassInfoEntry* e2) { duke@435: if(e1->_instance_words > e2->_instance_words) { duke@435: return -1; duke@435: } else if(e1->_instance_words < e2->_instance_words) { duke@435: return 1; duke@435: } duke@435: return 0; duke@435: } duke@435: duke@435: void KlassInfoEntry::print_on(outputStream* st) const { duke@435: ResourceMark rm; duke@435: const char* name;; duke@435: if (_klass->klass_part()->name() != NULL) { duke@435: name = _klass->klass_part()->external_name(); duke@435: } else { duke@435: if (_klass == Universe::klassKlassObj()) name = ""; else duke@435: if (_klass == Universe::arrayKlassKlassObj()) name = ""; else duke@435: if (_klass == Universe::objArrayKlassKlassObj()) name = ""; else duke@435: if (_klass == Universe::instanceKlassKlassObj()) name = ""; else duke@435: if (_klass == Universe::typeArrayKlassKlassObj()) name = ""; else duke@435: if (_klass == Universe::symbolKlassObj()) name = ""; else duke@435: if (_klass == Universe::boolArrayKlassObj()) name = ""; else duke@435: if (_klass == Universe::charArrayKlassObj()) name = ""; else duke@435: if (_klass == Universe::singleArrayKlassObj()) name = ""; else duke@435: if (_klass == Universe::doubleArrayKlassObj()) name = ""; else duke@435: if (_klass == Universe::byteArrayKlassObj()) name = ""; else duke@435: if (_klass == Universe::shortArrayKlassObj()) name = ""; else duke@435: if (_klass == Universe::intArrayKlassObj()) name = ""; else duke@435: if (_klass == Universe::longArrayKlassObj()) name = ""; else duke@435: if (_klass == Universe::methodKlassObj()) name = ""; else duke@435: if (_klass == Universe::constMethodKlassObj()) name = ""; else duke@435: if (_klass == Universe::methodDataKlassObj()) name = ""; else duke@435: if (_klass == Universe::constantPoolKlassObj()) name = ""; else duke@435: if (_klass == Universe::constantPoolCacheKlassObj()) name = ""; else duke@435: if (_klass == Universe::compiledICHolderKlassObj()) name = ""; else duke@435: name = ""; duke@435: } duke@435: // simplify the formatting (ILP32 vs LP64) - always cast the numbers to 64-bit ysr@446: st->print_cr(INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13) " %s", duke@435: (jlong) _instance_count, duke@435: (julong) _instance_words * HeapWordSize, duke@435: name); duke@435: } duke@435: duke@435: KlassInfoEntry* KlassInfoBucket::lookup(const klassOop k) { duke@435: KlassInfoEntry* elt = _list; duke@435: while (elt != NULL) { duke@435: if (elt->is_equal(k)) { duke@435: return elt; duke@435: } duke@435: elt = elt->next(); duke@435: } duke@435: elt = new KlassInfoEntry(k, list()); ysr@446: // We may be out of space to allocate the new entry. ysr@446: if (elt != NULL) { ysr@446: set_list(elt); ysr@446: } duke@435: return elt; duke@435: } duke@435: duke@435: void KlassInfoBucket::iterate(KlassInfoClosure* cic) { duke@435: KlassInfoEntry* elt = _list; duke@435: while (elt != NULL) { duke@435: cic->do_cinfo(elt); duke@435: elt = elt->next(); duke@435: } duke@435: } duke@435: duke@435: void KlassInfoBucket::empty() { duke@435: KlassInfoEntry* elt = _list; duke@435: _list = NULL; duke@435: while (elt != NULL) { duke@435: KlassInfoEntry* next = elt->next(); duke@435: delete elt; duke@435: elt = next; duke@435: } duke@435: } duke@435: duke@435: KlassInfoTable::KlassInfoTable(int size, HeapWord* ref) { ysr@446: _size = 0; duke@435: _ref = ref; ysr@446: _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, size); ysr@446: if (_buckets != NULL) { ysr@446: _size = size; ysr@446: for (int index = 0; index < _size; index++) { ysr@446: _buckets[index].initialize(); ysr@446: } duke@435: } duke@435: } duke@435: duke@435: KlassInfoTable::~KlassInfoTable() { ysr@446: if (_buckets != NULL) { ysr@446: for (int index = 0; index < _size; index++) { ysr@446: _buckets[index].empty(); ysr@446: } ysr@446: FREE_C_HEAP_ARRAY(KlassInfoBucket, _buckets); ysr@446: _size = 0; duke@435: } duke@435: } duke@435: duke@435: uint KlassInfoTable::hash(klassOop p) { duke@435: assert(Universe::heap()->is_in_permanent((HeapWord*)p), "all klasses in permgen"); duke@435: return (uint)(((uintptr_t)p - (uintptr_t)_ref) >> 2); duke@435: } duke@435: duke@435: KlassInfoEntry* KlassInfoTable::lookup(const klassOop k) { duke@435: uint idx = hash(k) % _size; ysr@446: assert(_buckets != NULL, "Allocation failure should have been caught"); duke@435: KlassInfoEntry* e = _buckets[idx].lookup(k); ysr@446: // Lookup may fail if this is a new klass for which we ysr@446: // could not allocate space for an new entry. ysr@446: assert(e == NULL || k == e->klass(), "must be equal"); duke@435: return e; duke@435: } duke@435: ysr@446: // Return false if the entry could not be recorded on account ysr@446: // of running out of space required to create a new entry. ysr@446: bool KlassInfoTable::record_instance(const oop obj) { duke@435: klassOop k = obj->klass(); duke@435: KlassInfoEntry* elt = lookup(k); ysr@446: // elt may be NULL if it's a new klass for which we ysr@446: // could not allocate space for a new entry in the hashtable. ysr@446: if (elt != NULL) { ysr@446: elt->set_count(elt->count() + 1); ysr@446: elt->set_words(elt->words() + obj->size()); ysr@446: return true; ysr@446: } else { ysr@446: return false; ysr@446: } duke@435: } duke@435: duke@435: void KlassInfoTable::iterate(KlassInfoClosure* cic) { ysr@446: assert(_size == 0 || _buckets != NULL, "Allocation failure should have been caught"); duke@435: for (int index = 0; index < _size; index++) { duke@435: _buckets[index].iterate(cic); duke@435: } duke@435: } duke@435: duke@435: int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) { duke@435: return (*e1)->compare(*e1,*e2); duke@435: } duke@435: duke@435: KlassInfoHisto::KlassInfoHisto(const char* title, int estimatedCount) : duke@435: _title(title) { duke@435: _elements = new (ResourceObj::C_HEAP) GrowableArray(estimatedCount,true); duke@435: } duke@435: duke@435: KlassInfoHisto::~KlassInfoHisto() { duke@435: delete _elements; duke@435: } duke@435: duke@435: void KlassInfoHisto::add(KlassInfoEntry* cie) { duke@435: elements()->append(cie); duke@435: } duke@435: duke@435: void KlassInfoHisto::sort() { duke@435: elements()->sort(KlassInfoHisto::sort_helper); duke@435: } duke@435: duke@435: void KlassInfoHisto::print_elements(outputStream* st) const { duke@435: // simplify the formatting (ILP32 vs LP64) - store the sum in 64-bit duke@435: jlong total = 0; duke@435: julong totalw = 0; duke@435: for(int i=0; i < elements()->length(); i++) { duke@435: st->print("%4d: ", i+1); duke@435: elements()->at(i)->print_on(st); duke@435: total += elements()->at(i)->count(); duke@435: totalw += elements()->at(i)->words(); duke@435: } ysr@446: st->print_cr("Total " INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13), duke@435: total, totalw * HeapWordSize); duke@435: } duke@435: duke@435: void KlassInfoHisto::print_on(outputStream* st) const { duke@435: st->print_cr("%s",title()); duke@435: print_elements(st); duke@435: } duke@435: duke@435: class HistoClosure : public KlassInfoClosure { duke@435: private: duke@435: KlassInfoHisto* _cih; duke@435: public: duke@435: HistoClosure(KlassInfoHisto* cih) : _cih(cih) {} duke@435: duke@435: void do_cinfo(KlassInfoEntry* cie) { duke@435: _cih->add(cie); duke@435: } duke@435: }; duke@435: duke@435: class RecordInstanceClosure : public ObjectClosure { duke@435: private: duke@435: KlassInfoTable* _cit; ysr@446: size_t _missed_count; duke@435: public: ysr@446: RecordInstanceClosure(KlassInfoTable* cit) : ysr@446: _cit(cit), _missed_count(0) {} duke@435: duke@435: void do_object(oop obj) { ysr@446: if (!_cit->record_instance(obj)) { ysr@446: _missed_count++; ysr@446: } duke@435: } ysr@446: ysr@446: size_t missed_count() { return _missed_count; } duke@435: }; duke@435: duke@435: void HeapInspection::heap_inspection(outputStream* st) { duke@435: ResourceMark rm; duke@435: HeapWord* ref; duke@435: duke@435: CollectedHeap* heap = Universe::heap(); ysr@777: bool is_shared_heap = false; duke@435: switch (heap->kind()) { ysr@777: case CollectedHeap::G1CollectedHeap: duke@435: case CollectedHeap::GenCollectedHeap: { ysr@777: is_shared_heap = true; ysr@777: SharedHeap* sh = (SharedHeap*)heap; ysr@777: sh->gc_prologue(false /* !full */); // get any necessary locks, etc. ysr@777: ref = sh->perm_gen()->used_region().start(); duke@435: break; duke@435: } duke@435: #ifndef SERIALGC duke@435: case CollectedHeap::ParallelScavengeHeap: { duke@435: ParallelScavengeHeap* psh = (ParallelScavengeHeap*)heap; duke@435: ref = psh->perm_gen()->object_space()->used_region().start(); duke@435: break; duke@435: } duke@435: #endif // SERIALGC duke@435: default: duke@435: ShouldNotReachHere(); // Unexpected heap kind for this op duke@435: } duke@435: // Collect klass instance info ysr@446: KlassInfoTable cit(KlassInfoTable::cit_size, ref); ysr@446: if (!cit.allocation_failed()) { ysr@446: // Iterate over objects in the heap ysr@446: RecordInstanceClosure ric(&cit); jmasa@952: // If this operation encounters a bad object when using CMS, jmasa@952: // consider using safe_object_iterate() which avoids perm gen jmasa@952: // objects that may contain bad references. ysr@446: Universe::heap()->object_iterate(&ric); duke@435: ysr@446: // Report if certain classes are not counted because of ysr@446: // running out of C-heap for the histogram. ysr@446: size_t missed_count = ric.missed_count(); ysr@446: if (missed_count != 0) { ysr@446: st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT ysr@446: " total instances in data below", ysr@446: missed_count); ysr@446: } ysr@446: // Sort and print klass instance info ysr@446: KlassInfoHisto histo("\n" ysr@446: " num #instances #bytes class name\n" ysr@446: "----------------------------------------------", ysr@446: KlassInfoHisto::histo_initial_size); ysr@446: HistoClosure hc(&histo); ysr@446: cit.iterate(&hc); ysr@446: histo.sort(); ysr@446: histo.print_on(st); ysr@446: } else { ysr@446: st->print_cr("WARNING: Ran out of C-heap; histogram not generated"); ysr@446: } duke@435: st->flush(); duke@435: ysr@777: if (is_shared_heap) { ysr@777: SharedHeap* sh = (SharedHeap*)heap; ysr@777: sh->gc_epilogue(false /* !full */); // release all acquired locks, etc. duke@435: } duke@435: } duke@435: duke@435: class FindInstanceClosure : public ObjectClosure { duke@435: private: duke@435: klassOop _klass; duke@435: GrowableArray* _result; duke@435: duke@435: public: duke@435: FindInstanceClosure(klassOop k, GrowableArray* result) : _klass(k), _result(result) {}; duke@435: duke@435: void do_object(oop obj) { duke@435: if (obj->is_a(_klass)) { duke@435: _result->append(obj); duke@435: } duke@435: } duke@435: }; duke@435: duke@435: void HeapInspection::find_instances_at_safepoint(klassOop k, GrowableArray* result) { duke@435: assert(SafepointSynchronize::is_at_safepoint(), "all threads are stopped"); duke@435: assert(Heap_lock->is_locked(), "should have the Heap_lock") duke@435: duke@435: // Ensure that the heap is parsable duke@435: Universe::heap()->ensure_parsability(false); // no need to retire TALBs duke@435: duke@435: // Iterate over objects in the heap duke@435: FindInstanceClosure fic(k, result); jmasa@952: // If this operation encounters a bad object when using CMS, jmasa@952: // consider using safe_object_iterate() which avoids perm gen jmasa@952: // objects that may contain bad references. duke@435: Universe::heap()->object_iterate(&fic); duke@435: }