Tue, 26 Feb 2008 15:57:49 -0800
6621728: Heap inspection should not crash in the face of C-heap exhaustion
Summary: Deal more gracefully with situations where C-heap scratch space cannot be had
Reviewed-by: jmasa
src/share/vm/memory/heapInspection.cpp | file | annotate | diff | comparison | revisions | |
src/share/vm/memory/heapInspection.hpp | file | annotate | diff | comparison | revisions |
1.1 --- a/src/share/vm/memory/heapInspection.cpp Fri Feb 22 17:17:14 2008 -0800 1.2 +++ b/src/share/vm/memory/heapInspection.cpp Tue Feb 26 15:57:49 2008 -0800 1.3 @@ -65,7 +65,7 @@ 1.4 name = "<no name>"; 1.5 } 1.6 // simplify the formatting (ILP32 vs LP64) - always cast the numbers to 64-bit 1.7 - st->print_cr("%13" FORMAT64_MODIFIER "d %13" FORMAT64_MODIFIER "u %s", 1.8 + st->print_cr(INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13) " %s", 1.9 (jlong) _instance_count, 1.10 (julong) _instance_words * HeapWordSize, 1.11 name); 1.12 @@ -80,7 +80,10 @@ 1.13 elt = elt->next(); 1.14 } 1.15 elt = new KlassInfoEntry(k, list()); 1.16 - set_list(elt); 1.17 + // We may be out of space to allocate the new entry. 1.18 + if (elt != NULL) { 1.19 + set_list(elt); 1.20 + } 1.21 return elt; 1.22 } 1.23 1.24 @@ -103,21 +106,25 @@ 1.25 } 1.26 1.27 KlassInfoTable::KlassInfoTable(int size, HeapWord* ref) { 1.28 - _size = size; 1.29 + _size = 0; 1.30 _ref = ref; 1.31 - _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, _size); 1.32 - 1.33 - for (int index = 0; index < _size; index++) { 1.34 - _buckets[index].initialize(); 1.35 + _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, size); 1.36 + if (_buckets != NULL) { 1.37 + _size = size; 1.38 + for (int index = 0; index < _size; index++) { 1.39 + _buckets[index].initialize(); 1.40 + } 1.41 } 1.42 } 1.43 1.44 KlassInfoTable::~KlassInfoTable() { 1.45 - for (int index = 0; index < _size; index++) { 1.46 - _buckets[index].empty(); 1.47 + if (_buckets != NULL) { 1.48 + for (int index = 0; index < _size; index++) { 1.49 + _buckets[index].empty(); 1.50 + } 1.51 + FREE_C_HEAP_ARRAY(KlassInfoBucket, _buckets); 1.52 + _size = 0; 1.53 } 1.54 - FREE_C_HEAP_ARRAY(KlassInfoBucket, _buckets); 1.55 - _size = 0; 1.56 } 1.57 1.58 uint KlassInfoTable::hash(klassOop p) { 1.59 @@ -127,19 +134,32 @@ 1.60 1.61 KlassInfoEntry* KlassInfoTable::lookup(const klassOop k) { 1.62 uint idx = hash(k) % _size; 1.63 + assert(_buckets != NULL, "Allocation failure should have been caught"); 1.64 KlassInfoEntry* e = _buckets[idx].lookup(k); 1.65 - assert(k == e->klass(), "must be equal"); 1.66 + // Lookup may fail if this is a new klass for which we 1.67 + // could not allocate space for an new entry. 1.68 + assert(e == NULL || k == e->klass(), "must be equal"); 1.69 return e; 1.70 } 1.71 1.72 -void KlassInfoTable::record_instance(const oop obj) { 1.73 +// Return false if the entry could not be recorded on account 1.74 +// of running out of space required to create a new entry. 1.75 +bool KlassInfoTable::record_instance(const oop obj) { 1.76 klassOop k = obj->klass(); 1.77 KlassInfoEntry* elt = lookup(k); 1.78 - elt->set_count(elt->count() + 1); 1.79 - elt->set_words(elt->words() + obj->size()); 1.80 + // elt may be NULL if it's a new klass for which we 1.81 + // could not allocate space for a new entry in the hashtable. 1.82 + if (elt != NULL) { 1.83 + elt->set_count(elt->count() + 1); 1.84 + elt->set_words(elt->words() + obj->size()); 1.85 + return true; 1.86 + } else { 1.87 + return false; 1.88 + } 1.89 } 1.90 1.91 void KlassInfoTable::iterate(KlassInfoClosure* cic) { 1.92 + assert(_size == 0 || _buckets != NULL, "Allocation failure should have been caught"); 1.93 for (int index = 0; index < _size; index++) { 1.94 _buckets[index].iterate(cic); 1.95 } 1.96 @@ -176,7 +196,7 @@ 1.97 total += elements()->at(i)->count(); 1.98 totalw += elements()->at(i)->words(); 1.99 } 1.100 - st->print_cr("Total %13" FORMAT64_MODIFIER "d %13" FORMAT64_MODIFIER "u", 1.101 + st->print_cr("Total " INT64_FORMAT_W(13) " " UINT64_FORMAT_W(13), 1.102 total, totalw * HeapWordSize); 1.103 } 1.104 1.105 @@ -199,12 +219,18 @@ 1.106 class RecordInstanceClosure : public ObjectClosure { 1.107 private: 1.108 KlassInfoTable* _cit; 1.109 + size_t _missed_count; 1.110 public: 1.111 - RecordInstanceClosure(KlassInfoTable* cit) : _cit(cit) {} 1.112 + RecordInstanceClosure(KlassInfoTable* cit) : 1.113 + _cit(cit), _missed_count(0) {} 1.114 1.115 void do_object(oop obj) { 1.116 - _cit->record_instance(obj); 1.117 + if (!_cit->record_instance(obj)) { 1.118 + _missed_count++; 1.119 + } 1.120 } 1.121 + 1.122 + size_t missed_count() { return _missed_count; } 1.123 }; 1.124 1.125 void HeapInspection::heap_inspection(outputStream* st) { 1.126 @@ -230,21 +256,32 @@ 1.127 ShouldNotReachHere(); // Unexpected heap kind for this op 1.128 } 1.129 // Collect klass instance info 1.130 + KlassInfoTable cit(KlassInfoTable::cit_size, ref); 1.131 + if (!cit.allocation_failed()) { 1.132 + // Iterate over objects in the heap 1.133 + RecordInstanceClosure ric(&cit); 1.134 + Universe::heap()->object_iterate(&ric); 1.135 1.136 - // Iterate over objects in the heap 1.137 - KlassInfoTable cit(KlassInfoTable::cit_size, ref); 1.138 - RecordInstanceClosure ric(&cit); 1.139 - Universe::heap()->object_iterate(&ric); 1.140 - 1.141 - // Sort and print klass instance info 1.142 - KlassInfoHisto histo("\n" 1.143 - " num #instances #bytes class name\n" 1.144 - "----------------------------------------------", 1.145 - KlassInfoHisto::histo_initial_size); 1.146 - HistoClosure hc(&histo); 1.147 - cit.iterate(&hc); 1.148 - histo.sort(); 1.149 - histo.print_on(st); 1.150 + // Report if certain classes are not counted because of 1.151 + // running out of C-heap for the histogram. 1.152 + size_t missed_count = ric.missed_count(); 1.153 + if (missed_count != 0) { 1.154 + st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT 1.155 + " total instances in data below", 1.156 + missed_count); 1.157 + } 1.158 + // Sort and print klass instance info 1.159 + KlassInfoHisto histo("\n" 1.160 + " num #instances #bytes class name\n" 1.161 + "----------------------------------------------", 1.162 + KlassInfoHisto::histo_initial_size); 1.163 + HistoClosure hc(&histo); 1.164 + cit.iterate(&hc); 1.165 + histo.sort(); 1.166 + histo.print_on(st); 1.167 + } else { 1.168 + st->print_cr("WARNING: Ran out of C-heap; histogram not generated"); 1.169 + } 1.170 st->flush(); 1.171 1.172 if (Universe::heap()->kind() == CollectedHeap::GenCollectedHeap) {
2.1 --- a/src/share/vm/memory/heapInspection.hpp Fri Feb 22 17:17:14 2008 -0800 2.2 +++ b/src/share/vm/memory/heapInspection.hpp Tue Feb 26 15:57:49 2008 -0800 2.3 @@ -98,8 +98,9 @@ 2.4 }; 2.5 KlassInfoTable(int size, HeapWord* ref); 2.6 ~KlassInfoTable(); 2.7 - void record_instance(const oop obj); 2.8 + bool record_instance(const oop obj); 2.9 void iterate(KlassInfoClosure* cic); 2.10 + bool allocation_failed() { return _buckets == NULL; } 2.11 }; 2.12 2.13 class KlassInfoHisto : public StackObj {