heapInspection.cpp 10.9 KB
Newer Older
D
duke 已提交
1
/*
X
xdono 已提交
2
 * Copyright 2002-2008 Sun Microsystems, Inc.  All Rights Reserved.
D
duke 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
 * 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 = "<klassKlass>";             else
    if (_klass == Universe::arrayKlassKlassObj())        name = "<arrayKlassKlass>";        else
    if (_klass == Universe::objArrayKlassKlassObj())     name = "<objArrayKlassKlass>";     else
    if (_klass == Universe::instanceKlassKlassObj())     name = "<instanceKlassKlass>";     else
    if (_klass == Universe::typeArrayKlassKlassObj())    name = "<typeArrayKlassKlass>";    else
    if (_klass == Universe::symbolKlassObj())            name = "<symbolKlass>";            else
    if (_klass == Universe::boolArrayKlassObj())         name = "<boolArrayKlass>";         else
    if (_klass == Universe::charArrayKlassObj())         name = "<charArrayKlass>";         else
    if (_klass == Universe::singleArrayKlassObj())       name = "<singleArrayKlass>";       else
    if (_klass == Universe::doubleArrayKlassObj())       name = "<doubleArrayKlass>";       else
    if (_klass == Universe::byteArrayKlassObj())         name = "<byteArrayKlass>";         else
    if (_klass == Universe::shortArrayKlassObj())        name = "<shortArrayKlass>";        else
    if (_klass == Universe::intArrayKlassObj())          name = "<intArrayKlass>";          else
    if (_klass == Universe::longArrayKlassObj())         name = "<longArrayKlass>";         else
    if (_klass == Universe::methodKlassObj())            name = "<methodKlass>";            else
    if (_klass == Universe::constMethodKlassObj())       name = "<constMethodKlass>";       else
    if (_klass == Universe::methodDataKlassObj())        name = "<methodDataKlass>";        else
    if (_klass == Universe::constantPoolKlassObj())      name = "<constantPoolKlass>";      else
    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
68
  st->print_cr(INT64_FORMAT_W(13) "  " UINT64_FORMAT_W(13) "  %s",
D
duke 已提交
69 70 71 72 73 74 75 76 77 78 79 80 81 82
               (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());
83 84 85 86
  // We may be out of space to allocate the new entry.
  if (elt != NULL) {
    set_list(elt);
  }
D
duke 已提交
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
  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) {
109
  _size = 0;
D
duke 已提交
110
  _ref = ref;
111 112 113 114 115 116
  _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, size);
  if (_buckets != NULL) {
    _size = size;
    for (int index = 0; index < _size; index++) {
      _buckets[index].initialize();
    }
D
duke 已提交
117 118 119 120
  }
}

KlassInfoTable::~KlassInfoTable() {
121 122 123 124 125 126
  if (_buckets != NULL) {
    for (int index = 0; index < _size; index++) {
      _buckets[index].empty();
    }
    FREE_C_HEAP_ARRAY(KlassInfoBucket, _buckets);
    _size = 0;
D
duke 已提交
127 128 129 130 131 132 133 134 135 136
  }
}

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;
137
  assert(_buckets != NULL, "Allocation failure should have been caught");
D
duke 已提交
138
  KlassInfoEntry*  e   = _buckets[idx].lookup(k);
139 140 141
  // 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");
D
duke 已提交
142 143 144
  return e;
}

145 146 147
// 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) {
D
duke 已提交
148 149
  klassOop      k = obj->klass();
  KlassInfoEntry* elt = lookup(k);
150 151 152 153 154 155 156 157 158
  // 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;
  }
D
duke 已提交
159 160 161
}

void KlassInfoTable::iterate(KlassInfoClosure* cic) {
162
  assert(_size == 0 || _buckets != NULL, "Allocation failure should have been caught");
D
duke 已提交
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
  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<KlassInfoEntry*>(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();
  }
199
  st->print_cr("Total " INT64_FORMAT_W(13) "  " UINT64_FORMAT_W(13),
D
duke 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
               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;
222
  size_t _missed_count;
D
duke 已提交
223
 public:
224 225
  RecordInstanceClosure(KlassInfoTable* cit) :
    _cit(cit), _missed_count(0) {}
D
duke 已提交
226 227

  void do_object(oop obj) {
228 229 230
    if (!_cit->record_instance(obj)) {
      _missed_count++;
    }
D
duke 已提交
231
  }
232 233

  size_t missed_count() { return _missed_count; }
D
duke 已提交
234 235 236 237 238 239 240
};

void HeapInspection::heap_inspection(outputStream* st) {
  ResourceMark rm;
  HeapWord* ref;

  CollectedHeap* heap = Universe::heap();
241
  bool is_shared_heap = false;
D
duke 已提交
242
  switch (heap->kind()) {
243
    case CollectedHeap::G1CollectedHeap:
D
duke 已提交
244
    case CollectedHeap::GenCollectedHeap: {
245 246 247 248
      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();
D
duke 已提交
249 250 251 252 253 254 255 256 257 258 259 260 261 262
      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
  KlassInfoTable cit(KlassInfoTable::cit_size, ref);
263 264 265
  if (!cit.allocation_failed()) {
    // Iterate over objects in the heap
    RecordInstanceClosure ric(&cit);
266 267 268
    // If this operation encounters a bad object when using CMS,
    // consider using safe_object_iterate() which avoids perm gen
    // objects that may contain bad references.
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
    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");
  }
D
duke 已提交
291 292
  st->flush();

293 294 295
  if (is_shared_heap) {
    SharedHeap* sh = (SharedHeap*)heap;
    sh->gc_epilogue(false /* !full */); // release all acquired locks, etc.
D
duke 已提交
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
  }
}

class FindInstanceClosure : public ObjectClosure {
 private:
  klassOop _klass;
  GrowableArray<oop>* _result;

 public:
  FindInstanceClosure(klassOop k, GrowableArray<oop>* 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<oop>* 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);
323 324 325
  // If this operation encounters a bad object when using CMS,
  // consider using safe_object_iterate() which avoids perm gen
  // objects that may contain bad references.
D
duke 已提交
326 327
  Universe::heap()->object_iterate(&fic);
}