1 /* 2 * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_MEMORY_HEAPINSPECTION_HPP 26 #define SHARE_MEMORY_HEAPINSPECTION_HPP 27 28 #include "memory/allocation.hpp" 29 #include "oops/objArrayOop.hpp" 30 #include "oops/oop.hpp" 31 #include "oops/annotations.hpp" 32 #include "utilities/macros.hpp" 33 #include "gc/shared/workgroup.hpp" 34 #if INCLUDE_SERVICES 35 36 37 // HeapInspection 38 39 // KlassInfoTable is a bucket hash table that 40 // maps Klass*s to extra information: 41 // instance count and instance word size. 42 // 43 // A KlassInfoBucket is the head of a link list 44 // of KlassInfoEntry's 45 // 46 // KlassInfoHisto is a growable array of pointers 47 // to KlassInfoEntry's and is used to sort 48 // the entries. 49 50 class KlassInfoEntry: public CHeapObj<mtInternal> { 51 private: 52 KlassInfoEntry* _next; 53 Klass* _klass; 54 long _instance_count; 55 size_t _instance_words; 56 long _index; 57 bool _do_print; // True if we should print this class when printing the class hierarchy. 58 GrowableArray<KlassInfoEntry*>* _subclasses; 59 60 public: 61 KlassInfoEntry(Klass* k, KlassInfoEntry* next) : 62 _next(next), _klass(k), _instance_count(0), _instance_words(0), _index(-1), 63 _do_print(false), _subclasses(NULL) 64 {} 65 ~KlassInfoEntry(); 66 KlassInfoEntry* next() const { return _next; } 67 bool is_equal(const Klass* k) { return k == _klass; } 68 Klass* klass() const { return _klass; } 69 long count() const { return _instance_count; } 70 void set_count(long ct) { _instance_count = ct; } 71 size_t words() const { return _instance_words; } 72 void set_words(size_t wds) { _instance_words = wds; } 73 void set_index(long index) { _index = index; } 74 long index() const { return _index; } 75 GrowableArray<KlassInfoEntry*>* subclasses() const { return _subclasses; } 76 void add_subclass(KlassInfoEntry* cie); 77 void set_do_print(bool do_print) { _do_print = do_print; } 78 bool do_print() const { return _do_print; } 79 int compare(KlassInfoEntry* e1, KlassInfoEntry* e2); 80 void print_on(outputStream* st) const; 81 const char* name() const; 82 }; 83 84 class KlassInfoClosure : public StackObj { 85 public: 86 // Called for each KlassInfoEntry. 87 virtual void do_cinfo(KlassInfoEntry* cie) = 0; 88 }; 89 90 class KlassInfoBucket: public CHeapObj<mtInternal> { 91 private: 92 KlassInfoEntry* _list; 93 KlassInfoEntry* list() { return _list; } 94 void set_list(KlassInfoEntry* l) { _list = l; } 95 public: 96 KlassInfoEntry* lookup(Klass* k); 97 void initialize() { _list = NULL; } 98 void empty(); 99 void iterate(KlassInfoClosure* cic); 100 }; 101 102 class KlassInfoTable: public StackObj { 103 private: 104 static const int _num_buckets = 20011; 105 size_t _size_of_instances_in_words; 106 107 // An aligned reference address (typically the least 108 // address in the perm gen) used for hashing klass 109 // objects. 110 HeapWord* _ref; 111 112 KlassInfoBucket* _buckets; 113 uint hash(const Klass* p); 114 KlassInfoEntry* lookup(Klass* k); // allocates if not found! 115 116 class AllClassesFinder; 117 118 public: 119 KlassInfoTable(bool add_all_classes); 120 ~KlassInfoTable(); 121 bool record_instance(const oop obj); 122 void iterate(KlassInfoClosure* cic); 123 bool allocation_failed() { return _buckets == NULL; } 124 size_t size_of_instances_in_words() const; 125 bool merge(KlassInfoTable* table); 126 bool merge_entry(const KlassInfoEntry* cie); 127 128 friend class KlassInfoHisto; 129 friend class KlassHierarchy; 130 }; 131 132 class KlassHierarchy : AllStatic { 133 public: 134 static void print_class_hierarchy(outputStream* st, bool print_interfaces, bool print_subclasses, 135 char* classname); 136 137 private: 138 static void set_do_print_for_class_hierarchy(KlassInfoEntry* cie, KlassInfoTable* cit, 139 bool print_subclasse); 140 static void print_class(outputStream* st, KlassInfoEntry* cie, bool print_subclasses); 141 }; 142 143 class KlassInfoHisto : public StackObj { 144 private: 145 static const int _histo_initial_size = 1000; 146 KlassInfoTable *_cit; 147 GrowableArray<KlassInfoEntry*>* _elements; 148 GrowableArray<KlassInfoEntry*>* elements() const { return _elements; } 149 static int sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2); 150 void print_elements(outputStream* st) const; 151 bool is_selected(const char *col_name); 152 153 template <class T> static int count_bytes(T* x) { 154 return (HeapWordSize * ((x) ? (x)->size() : 0)); 155 } 156 157 template <class T> static int count_bytes_array(T* x) { 158 if (x == NULL) { 159 return 0; 160 } 161 if (x->length() == 0) { 162 // This is a shared array, e.g., Universe::the_empty_int_array(). Don't 163 // count it to avoid double-counting. 164 return 0; 165 } 166 return HeapWordSize * x->size(); 167 } 168 169 static void print_julong(outputStream* st, int width, julong n) { 170 int num_spaces = width - julong_width(n); 171 if (num_spaces > 0) { 172 st->print("%*s", num_spaces, ""); 173 } 174 st->print(JULONG_FORMAT, n); 175 } 176 177 static int julong_width(julong n) { 178 if (n == 0) { 179 return 1; 180 } 181 int w = 0; 182 while (n > 0) { 183 n /= 10; 184 w += 1; 185 } 186 return w; 187 } 188 189 static int col_width(julong n, const char *name) { 190 int w = julong_width(n); 191 int min = (int)(strlen(name)); 192 if (w < min) { 193 w = min; 194 } 195 // add a leading space for separation. 196 return w + 1; 197 } 198 199 public: 200 KlassInfoHisto(KlassInfoTable* cit); 201 ~KlassInfoHisto(); 202 void add(KlassInfoEntry* cie); 203 void print_histo_on(outputStream* st); 204 void sort(); 205 }; 206 207 #endif // INCLUDE_SERVICES 208 209 // These declarations are needed since the declaration of KlassInfoTable and 210 // KlassInfoClosure are guarded by #if INLCUDE_SERVICES 211 class KlassInfoTable; 212 class KlassInfoClosure; 213 214 class HeapInspection : public StackObj { 215 public: 216 void heap_inspection(outputStream* st, size_t parallel_thread_num = 1) NOT_SERVICES_RETURN; 217 size_t populate_table(KlassInfoTable* cit, BoolObjectClosure* filter = NULL, size_t parallel_thread_num = 1) NOT_SERVICES_RETURN_(0); 218 static void find_instances_at_safepoint(Klass* k, GrowableArray<oop>* result) NOT_SERVICES_RETURN; 219 private: 220 void iterate_over_heap(KlassInfoTable* cit, BoolObjectClosure* filter = NULL); 221 }; 222 223 class ParHeapInspectTask : public AbstractGangTask { 224 private: 225 CollectedHeap* _heap; 226 KlassInfoTable* _shared_cit; 227 BoolObjectClosure* _filter; 228 size_t* _shared_missed_count; 229 bool _success; 230 Mutex _mutex; 231 size_t _par_thread_num; 232 233 public: 234 ParHeapInspectTask(CollectedHeap* heap, KlassInfoTable* shared_cit, 235 BoolObjectClosure* filter, size_t* shared_missed_count, 236 size_t parallel_thread_num) : 237 AbstractGangTask("Iterating heap"), 238 _heap(heap), 239 _shared_cit(shared_cit), 240 _filter(filter), 241 _shared_missed_count(shared_missed_count), 242 _success(true), 243 _mutex(Mutex::leaf, "Parallel heap iteration data merge lock"), 244 _par_thread_num(parallel_thread_num) { } 245 246 bool is_success() { 247 return _success; 248 } 249 250 CollectedHeap* getHeap() { 251 return _heap; 252 } 253 virtual void work(uint worker_id); 254 virtual void do_object_iterate_parallel(ObjectClosure* closure, uint worker_id) = 0; 255 }; 256 257 258 259 #endif // SHARE_MEMORY_HEAPINSPECTION_HPP