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