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: