1 /* 2 * Copyright (c) 2014, 2026, 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 #include "classfile/classLoaderData.inline.hpp" 26 #include "classfile/classLoaderDataGraph.hpp" 27 #include "classfile/classLoaderStats.hpp" 28 #include "memory/classLoaderMetaspace.hpp" 29 #include "oops/objArrayKlass.hpp" 30 #include "oops/oop.inline.hpp" 31 #include "utilities/globalDefinitions.hpp" 32 33 34 class ClassStatsClosure : public KlassClosure { 35 // Some klasses should not be reported by ClassStatistics 36 bool exclude_klass(Klass* k) const { 37 // Direct instances of ObjArrayKlass represent the Java types that Java code can see. 38 // RefArrayKlass/FlatArrayKlass describe different implementations of the arrays, filter them out. 39 return k->is_objArray_klass() && k->kind() != Klass::KlassKind::ObjArrayKlassKind; 40 } 41 42 public: 43 int _num_classes; 44 45 ClassStatsClosure() : 46 _num_classes(0) { 47 } 48 49 virtual void do_klass(Klass* k) { 50 if (!exclude_klass(k)) { 51 _num_classes++; 52 } 53 } 54 55 }; 56 57 void ClassLoaderStatsClosure::do_cld(ClassLoaderData* cld) { 58 // Class loaders are not kept alive so this closure must only be 59 // used during a safepoint. 60 assert_at_safepoint(); 61 oop cl = cld->class_loader_no_keepalive(); 62 63 // The hashtable key is the ClassLoader oop since we want to account 64 // for "real" classes and hidden classes together 65 bool added = false; 66 ClassLoaderStats* cls = _stats->put_if_absent(cl, &added); 67 if (added) { 68 cls->_class_loader = cl; 69 _total_loaders++; 70 } 71 assert(cls->_class_loader == cl, "Sanity"); 72 73 if (!cld->has_class_mirror_holder()) { 74 cls->_cld = cld; 75 } 76 77 if (cl != nullptr) { 78 cls->_parent = java_lang_ClassLoader::parent_no_keepalive(cl); 79 addEmptyParents(cls->_parent); 80 } 81 82 ClassStatsClosure csc; 83 cld->classes_do(&csc); 84 bool is_hidden = false; 85 if(cld->has_class_mirror_holder()) { 86 // If cld has a class holder then it must be hidden. 87 // Either way, count it as a hidden class. 88 cls->_hidden_classes_count += csc._num_classes; 89 } else { 90 cls->_classes_count = csc._num_classes; 91 } 92 _total_classes += csc._num_classes; 93 94 ClassLoaderMetaspace* ms = cld->metaspace_or_null(); 95 if (ms != nullptr) { 96 size_t used_words, capacity_words; 97 ms->usage_numbers(&used_words, nullptr, &capacity_words); 98 size_t used_bytes = used_words * BytesPerWord; 99 size_t capacity_bytes = capacity_words * BytesPerWord; 100 if(cld->has_class_mirror_holder()) { 101 cls->_hidden_chunk_sz += capacity_bytes; 102 cls->_hidden_block_sz += used_bytes; 103 } else { 104 cls->_chunk_sz = capacity_bytes; 105 cls->_block_sz = used_bytes; 106 } 107 _total_chunk_sz += capacity_bytes; 108 _total_block_sz += used_bytes; 109 } 110 } 111 112 // Handles the difference in pointer width on 32 and 64 bit platforms 113 #ifdef _LP64 114 #define SPACE "%8s" 115 #else 116 #define SPACE "%s" 117 #endif 118 119 120 bool ClassLoaderStatsClosure::do_entry(oop const& key, ClassLoaderStats const& cls) { 121 Klass* class_loader_klass = (cls._class_loader == nullptr ? nullptr : cls._class_loader->klass()); 122 Klass* parent_klass = (cls._parent == nullptr ? nullptr : cls._parent->klass()); 123 124 _out->print(INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " %6zu %8zu %8zu ", 125 p2i(class_loader_klass), p2i(parent_klass), p2i(cls._cld), 126 cls._classes_count, 127 cls._chunk_sz, cls._block_sz); 128 if (class_loader_klass != nullptr) { 129 _out->print("%s", class_loader_klass->external_name()); 130 } else { 131 _out->print("<boot class loader>"); 132 } 133 _out->cr(); 134 if (cls._hidden_classes_count > 0) { 135 _out->print_cr(SPACE SPACE SPACE " %6zu %8zu %8zu + hidden classes", 136 "", "", "", 137 cls._hidden_classes_count, 138 cls._hidden_chunk_sz, cls._hidden_block_sz); 139 } 140 return true; 141 } 142 143 144 void ClassLoaderStatsClosure::print() { 145 _out->print_cr("ClassLoader" SPACE " Parent" SPACE " CLD*" SPACE " Classes ChunkSz BlockSz Type", "", "", ""); 146 _stats->iterate(this); 147 _out->print("Total = %-6zu", _total_loaders); 148 _out->print(SPACE SPACE SPACE " ", "", "", ""); 149 _out->print_cr("%6zu %8zu %8zu ", 150 _total_classes, 151 _total_chunk_sz, 152 _total_block_sz); 153 _out->print_cr("ChunkSz: Total size of all allocated metaspace chunks"); 154 _out->print_cr("BlockSz: Total size of all allocated metaspace blocks (each chunk has several blocks)"); 155 } 156 157 158 void ClassLoaderStatsClosure::addEmptyParents(oop cl) { 159 while (cl != nullptr && java_lang_ClassLoader::loader_data_acquire(cl) == nullptr) { 160 // This classloader has not loaded any classes 161 bool added = false; 162 ClassLoaderStats* cls = _stats->put_if_absent(cl, &added); 163 if (added) { 164 cls->_class_loader = cl; 165 cls->_parent = java_lang_ClassLoader::parent_no_keepalive(cl); 166 _total_loaders++; 167 } 168 assert(cls->_class_loader == cl, "Sanity"); 169 170 cl = java_lang_ClassLoader::parent_no_keepalive(cl); 171 } 172 } 173 174 175 void ClassLoaderStatsVMOperation::doit() { 176 ClassLoaderStatsClosure clsc (_out); 177 ClassLoaderDataGraph::loaded_cld_do(&clsc); 178 clsc.print(); 179 } 180 181 182 void ClassLoaderStatsDCmd::execute(DCmdSource source, TRAPS) { 183 ClassLoaderStatsVMOperation op(output()); 184 VMThread::execute(&op); 185 } --- EOF ---