Mercurial > hg > icedtea8-forest > hotspot
changeset 9998:88515137e73f icedtea-3.9.0pre02
Merge jdk8u172-b11
author | andrew |
---|---|
date | Mon, 27 Aug 2018 16:38:00 +0100 |
parents | 6f7d65e42104 (current diff) 083a9d656210 (diff) |
children | a3f75e600099 |
files | .hgtags src/os/bsd/vm/os_bsd.cpp src/share/vm/classfile/vmSymbols.hpp src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp src/share/vm/memory/metaspace.cpp src/share/vm/memory/metaspace.hpp src/share/vm/opto/chaitin.cpp src/share/vm/opto/loopopts.cpp src/share/vm/opto/matcher.cpp src/share/vm/prims/jni.cpp src/share/vm/runtime/thread.cpp src/share/vm/runtime/vm_operations.hpp src/share/vm/services/diagnosticCommand.cpp src/share/vm/services/diagnosticCommand.hpp test/TEST.groups |
diffstat | 33 files changed, 1293 insertions(+), 198 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Sun Aug 19 04:29:57 2018 +0100 +++ b/.hgtags Mon Aug 27 16:38:00 2018 +0100 @@ -1200,3 +1200,15 @@ cb5711bf53d9278904c1ee63630a5c82189cb09a icedtea-3.8.0 cb5711bf53d9278904c1ee63630a5c82189cb09a icedtea-3.9.0pre00 0458118b5f190097099f2ea7b025cb2d5aeb0429 icedtea-3.9.0pre01 +23addae1b843a5027df6b4194f8c8de788da55ae jdk8u171-b11 +f299cf0b7baea1ae85f139f97adb9ab5499f402a jdk8u172-b00 +d10254debf7c1342416062bf1ba5258f16a8ce00 jdk8u172-b01 +653d9e0cd3f4023675c9eece7f0d563287f1d34f jdk8u172-b02 +771d9e1fbe1ae2ec4d5d937ebcbfd18e9c800098 jdk8u172-b03 +efd7a4e211e8fddf52053d4b033d8d307f356bc3 jdk8u172-b04 +4235fb1dceebde1192498ef388a32e56b1ed5a46 jdk8u172-b05 +68b234d5df6f01f3c677a114ecd6878c25f23f3c jdk8u172-b06 +a311a45523b19d59f77e76b0441a2085bb5355c8 jdk8u172-b07 +5c1f180db1650f0f33e6005c1366f0d68242f1ad jdk8u172-b08 +aafd1bb21e2636ba982d3eae162f5c635a1df03a jdk8u172-b09 +dcd3ace969fcde4eedaddba629647656289d4264 jdk8u172-b10
--- a/src/os/bsd/vm/os_bsd.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/os/bsd/vm/os_bsd.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -1681,14 +1681,9 @@ dlclose(handle); #elif defined(__APPLE__) - uint32_t count; - uint32_t i; - - count = _dyld_image_count(); - for (i = 1; i < count; i++) { - const char *name = _dyld_get_image_name(i); - intptr_t slide = _dyld_get_image_vmaddr_slide(i); - st->print_cr(PTR_FORMAT " \t%s", slide, name); + for (uint32_t i = 1; i < _dyld_image_count(); i++) { + st->print_cr(PTR_FORMAT " \t%s", _dyld_get_image_header(i), + _dyld_get_image_name(i)); } #else st->print_cr("Error: Cannot print dynamic libraries.");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/classLoaderStats.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/classLoaderStats.hpp" +#include "utilities/globalDefinitions.hpp" + + +class ClassStatsClosure : public KlassClosure { +public: + int _num_classes; + + ClassStatsClosure() : + _num_classes(0) { + } + + virtual void do_klass(Klass* k) { + _num_classes++; + } +}; + + +void ClassLoaderStatsClosure::do_cld(ClassLoaderData* cld) { + oop cl = cld->class_loader(); + ClassLoaderStats* cls; + + // The hashtable key is the ClassLoader oop since we want to account + // for "real" classes and anonymous classes together + ClassLoaderStats** cls_ptr = _stats->get(cl); + if (cls_ptr == NULL) { + cls = new ClassLoaderStats(); + _stats->put(cl, cls); + _total_loaders++; + } else { + cls = *cls_ptr; + } + + if (!cld->is_anonymous()) { + cls->_cld = cld; + } + + cls->_class_loader = cl; + if (cl != NULL) { + cls->_parent = java_lang_ClassLoader::parent(cl); + addEmptyParents(cls->_parent); + } + + ClassStatsClosure csc; + cld->classes_do(&csc); + if(cld->is_anonymous()) { + cls->_anon_classes_count += csc._num_classes; + } else { + cls->_classes_count = csc._num_classes; + } + _total_classes += csc._num_classes; + + Metaspace* ms = cld->metaspace_or_null(); + if (ms != NULL) { + if(cld->is_anonymous()) { + cls->_anon_chunk_sz += ms->allocated_chunks_bytes(); + cls->_anon_block_sz += ms->allocated_blocks_bytes(); + } else { + cls->_chunk_sz = ms->allocated_chunks_bytes(); + cls->_block_sz = ms->allocated_blocks_bytes(); + } + _total_chunk_sz += ms->allocated_chunks_bytes(); + _total_block_sz += ms->allocated_blocks_bytes(); + } +} + + +// Handles the difference in pointer width on 32 and 64 bit platforms +#ifdef _LP64 + #define SPACE "%8s" +#else + #define SPACE "%s" +#endif + + +bool ClassLoaderStatsClosure::do_entry(oop const& key, ClassLoaderStats* const& cls) { + Klass* class_loader_klass = (cls->_class_loader == NULL ? NULL : cls->_class_loader->klass()); + Klass* parent_klass = (cls->_parent == NULL ? NULL : cls->_parent->klass()); + + _out->print(INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " " UINTX_FORMAT_W(6) " " SIZE_FORMAT_W(8) " " SIZE_FORMAT_W(8) " ", + p2i(class_loader_klass), p2i(parent_klass), p2i(cls->_cld), + cls->_classes_count, + cls->_chunk_sz, cls->_block_sz); + if (class_loader_klass != NULL) { + _out->print("%s", class_loader_klass->external_name()); + } else { + _out->print("<boot class loader>"); + } + _out->cr(); + if (cls->_anon_classes_count > 0) { + _out->print_cr(SPACE SPACE SPACE " " UINTX_FORMAT_W(6) " " SIZE_FORMAT_W(8) " " SIZE_FORMAT_W(8) " + unsafe anonymous classes", + "", "", "", + cls->_anon_classes_count, + cls->_anon_chunk_sz, cls->_anon_block_sz); + } + return true; +} + + +void ClassLoaderStatsClosure::print() { + _out->print_cr("ClassLoader" SPACE " Parent" SPACE " CLD*" SPACE " Classes ChunkSz BlockSz Type", "", "", ""); + _stats->iterate(this); + _out->print("Total = " UINTX_FORMAT_W(-6), _total_loaders); + _out->print(SPACE SPACE SPACE " ", "", "", ""); + _out->print_cr(UINTX_FORMAT_W(6) " " SIZE_FORMAT_W(8) " " SIZE_FORMAT_W(8) " ", + _total_classes, + _total_chunk_sz, + _total_block_sz); + _out->print_cr("ChunkSz: Total size of all allocated metaspace chunks"); + _out->print_cr("BlockSz: Total size of all allocated metaspace blocks (each chunk has several blocks)"); +} + + +void ClassLoaderStatsClosure::addEmptyParents(oop cl) { + while (cl != NULL && java_lang_ClassLoader::loader_data(cl) == NULL) { + // This classloader has not loaded any classes + ClassLoaderStats** cls_ptr = _stats->get(cl); + if (cls_ptr == NULL) { + // It does not exist in our table - add it + ClassLoaderStats* cls = new ClassLoaderStats(); + cls->_class_loader = cl; + cls->_parent = java_lang_ClassLoader::parent(cl); + _stats->put(cl, cls); + _total_loaders++; + } + + cl = java_lang_ClassLoader::parent(cl); + } +} + + +void ClassLoaderStatsVMOperation::doit() { + ClassLoaderStatsClosure clsc (_out); + ClassLoaderDataGraph::cld_do(&clsc); + clsc.print(); +} + + +void ClassLoaderStatsDCmd::execute(DCmdSource source, TRAPS) { + ClassLoaderStatsVMOperation op(output()); + VMThread::execute(&op); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/classLoaderStats.hpp Mon Aug 27 16:38:00 2018 +0100 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_CLASSFILE_CLASSLOADERSTATS_HPP +#define SHARE_VM_CLASSFILE_CLASSLOADERSTATS_HPP + + +#include "classfile/classLoaderData.hpp" +#include "oops/klass.hpp" +#include "oops/oopsHierarchy.hpp" +#include "runtime/vm_operations.hpp" +#include "services/diagnosticCommand.hpp" +#include "utilities/resourceHash.hpp" + + +class ClassLoaderStatsDCmd : public DCmd { +public: + ClassLoaderStatsDCmd(outputStream* output, bool heap) : + DCmd(output, heap) { + } + + static const char* name() { + return "VM.classloader_stats"; + } + + static const char* description() { + return "Print statistics about all ClassLoaders."; + } + + static const char* impact() { + return "Low"; + } + + virtual void execute(DCmdSource source, TRAPS); + + static int num_arguments() { + return 0; + } + + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } +}; + + +class ClassLoaderStats : public ResourceObj { +public: + ClassLoaderData* _cld; + oop _class_loader; + oop _parent; + + size_t _chunk_sz; + size_t _block_sz; + uintx _classes_count; + + size_t _anon_chunk_sz; + size_t _anon_block_sz; + uintx _anon_classes_count; + + ClassLoaderStats() : + _cld(0), + _class_loader(0), + _parent(0), + _chunk_sz(0), + _block_sz(0), + _classes_count(0), + _anon_block_sz(0), + _anon_chunk_sz(0), + _anon_classes_count(0) { + } +}; + + +class ClassLoaderStatsClosure : public CLDClosure { +protected: + static bool oop_equals(oop const& s1, oop const& s2) { + return s1 == s2; + } + + static unsigned oop_hash(oop const& s1) { + unsigned hash = (unsigned)((uintptr_t)&s1); + return hash ^ (hash >> LogMinObjAlignment); + } + + typedef ResourceHashtable<oop, ClassLoaderStats*, + ClassLoaderStatsClosure::oop_hash, ClassLoaderStatsClosure::oop_equals> StatsTable; + + outputStream* _out; + StatsTable* _stats; + uintx _total_loaders; + uintx _total_classes; + size_t _total_chunk_sz; + size_t _total_block_sz; + +public: + ClassLoaderStatsClosure(outputStream* out) : + _out(out), + _total_loaders(0), + _total_block_sz(0), + _total_chunk_sz(0), + _total_classes(0), + _stats(new StatsTable()) { + } + + virtual void do_cld(ClassLoaderData* cld); + virtual bool do_entry(oop const& key, ClassLoaderStats* const& cls); + void print(); + +private: + void addEmptyParents(oop cl); +}; + + +class ClassLoaderStatsVMOperation : public VM_Operation { + outputStream* _out; + +public: + ClassLoaderStatsVMOperation(outputStream* out) : + _out(out) { + } + + VMOp_Type type() const { + return VMOp_ClassLoaderStatsOperation; + } + + void doit(); +}; + +#endif // SHARE_VM_CLASSFILE_CLASSLOADERSTATS_HPP
--- a/src/share/vm/classfile/vmSymbols.hpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/classfile/vmSymbols.hpp Mon Aug 27 16:38:00 2018 +0100 @@ -573,6 +573,11 @@ template(java_lang_management_ThreadInfo_constructor_signature, "(Ljava/lang/Thread;ILjava/lang/Object;Ljava/lang/Thread;JJJJ[Ljava/lang/StackTraceElement;)V") \ template(java_lang_management_ThreadInfo_with_locks_constructor_signature, "(Ljava/lang/Thread;ILjava/lang/Object;Ljava/lang/Thread;JJJJ[Ljava/lang/StackTraceElement;[Ljava/lang/Object;[I[Ljava/lang/Object;)V") \ template(long_long_long_long_void_signature, "(JJJJ)V") \ + template(finalizer_histogram_klass, "java/lang/ref/FinalizerHistogram") \ + template(void_finalizer_histogram_entry_array_signature, "()[Ljava/lang/ref/FinalizerHistogram$Entry;") \ + template(get_finalizer_histogram_name, "getFinalizerHistogram") \ + template(finalizer_histogram_entry_name_field, "className") \ + template(finalizer_histogram_entry_count_field, "instanceCount") \ \ template(java_lang_management_MemoryPoolMXBean, "java/lang/management/MemoryPoolMXBean") \ template(java_lang_management_MemoryManagerMXBean, "java/lang/management/MemoryManagerMXBean") \
--- a/src/share/vm/memory/metaspace.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/memory/metaspace.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -154,7 +154,7 @@ // Map a size to a list index assuming that there are lists // for special, small, medium, and humongous chunks. - static ChunkIndex list_index(size_t size); + ChunkIndex list_index(size_t size); // Remove the chunk from its freelist. It is // expected to be on one of the _free_chunks[] lists. @@ -531,9 +531,8 @@ size_t free_bytes(); - Metachunk* get_new_chunk(size_t word_size, - size_t grow_chunks_by_words, - size_t medium_chunk_bunch); + Metachunk* get_new_chunk(size_t chunk_word_size, + size_t suggested_commit_granularity); bool expand_node_by(VirtualSpaceNode* node, size_t min_words, @@ -687,19 +686,27 @@ MediumChunkMultiple = 4 }; - bool is_class() { return _mdtype == Metaspace::ClassType; } + static size_t specialized_chunk_size(bool is_class) { return is_class ? ClassSpecializedChunk : SpecializedChunk; } + static size_t small_chunk_size(bool is_class) { return is_class ? ClassSmallChunk : SmallChunk; } + static size_t medium_chunk_size(bool is_class) { return is_class ? ClassMediumChunk : MediumChunk; } + + static size_t smallest_chunk_size(bool is_class) { return specialized_chunk_size(is_class); } // Accessors - size_t specialized_chunk_size() { return (size_t) is_class() ? ClassSpecializedChunk : SpecializedChunk; } - size_t small_chunk_size() { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; } - size_t medium_chunk_size() { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; } - size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; } - - size_t smallest_chunk_size() { return specialized_chunk_size(); } + bool is_class() const { return _mdtype == Metaspace::ClassType; } + + size_t specialized_chunk_size() const { return specialized_chunk_size(is_class()); } + size_t small_chunk_size() const { return small_chunk_size(is_class()); } + size_t medium_chunk_size() const { return medium_chunk_size(is_class()); } + + size_t smallest_chunk_size() const { return smallest_chunk_size(is_class()); } + + size_t medium_chunk_bunch() const { return medium_chunk_size() * MediumChunkMultiple; } size_t allocated_blocks_words() const { return _allocated_blocks_words; } size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; } size_t allocated_chunks_words() const { return _allocated_chunks_words; } + size_t allocated_chunks_bytes() const { return _allocated_chunks_words * BytesPerWord; } size_t allocated_chunks_count() const { return _allocated_chunks_count; } bool is_humongous(size_t word_size) { return word_size > medium_chunk_size(); } @@ -718,10 +725,13 @@ // decremented for all the Metachunks in-use by this SpaceManager. void dec_total_from_size_metrics(); - // Set the sizes for the initial chunks. - void get_initial_chunk_sizes(Metaspace::MetaspaceType type, - size_t* chunk_word_size, - size_t* class_chunk_word_size); + // Adjust the initial chunk size to match one of the fixed chunk list sizes, + // or return the unadjusted size if the requested size is humongous. + static size_t adjust_initial_chunk_size(size_t requested, bool is_class_space); + size_t adjust_initial_chunk_size(size_t requested) const; + + // Get the initial chunks size for this metaspace type. + size_t get_initial_chunk_size(Metaspace::MetaspaceType type) const; size_t sum_capacity_in_chunks_in_use() const; size_t sum_used_in_chunks_in_use() const; @@ -732,7 +742,7 @@ size_t sum_count_in_chunks_in_use(); size_t sum_count_in_chunks_in_use(ChunkIndex i); - Metachunk* get_new_chunk(size_t word_size, size_t grow_chunks_by_words); + Metachunk* get_new_chunk(size_t chunk_word_size); // Block allocation and deallocation. // Allocates a block from the current chunk @@ -1200,7 +1210,7 @@ } size_t VirtualSpaceList::free_bytes() { - return virtual_space_list()->free_words_in_vs() * BytesPerWord; + return current_virtual_space()->free_words_in_vs() * BytesPerWord; } // Allocate another meta virtual space and add it to the list. @@ -1319,12 +1329,10 @@ return false; } -Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size, - size_t grow_chunks_by_words, - size_t medium_chunk_bunch) { +Metachunk* VirtualSpaceList::get_new_chunk(size_t chunk_word_size, size_t suggested_commit_granularity) { // Allocate a chunk out of the current virtual space. - Metachunk* next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); + Metachunk* next = current_virtual_space()->get_chunk_vs(chunk_word_size); if (next != NULL) { return next; @@ -1333,8 +1341,8 @@ // The expand amount is currently only determined by the requested sizes // and not how much committed memory is left in the current virtual space. - size_t min_word_size = align_size_up(grow_chunks_by_words, Metaspace::commit_alignment_words()); - size_t preferred_word_size = align_size_up(medium_chunk_bunch, Metaspace::commit_alignment_words()); + size_t min_word_size = align_size_up(chunk_word_size, Metaspace::commit_alignment_words()); + size_t preferred_word_size = align_size_up(suggested_commit_granularity, Metaspace::commit_alignment_words()); if (min_word_size >= preferred_word_size) { // Can happen when humongous chunks are allocated. preferred_word_size = min_word_size; @@ -1342,7 +1350,7 @@ bool expanded = expand_by(min_word_size, preferred_word_size); if (expanded) { - next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); + next = current_virtual_space()->get_chunk_vs(chunk_word_size); assert(next != NULL, "The allocation was expected to succeed after the expansion"); } @@ -1744,7 +1752,11 @@ st->print_cr("Sum free chunk total " SIZE_FORMAT " count " SIZE_FORMAT, sum_free_chunks(), sum_free_chunks_count()); } + ChunkList* ChunkManager::free_chunks(ChunkIndex index) { + assert(index == SpecializedIndex || index == SmallIndex || index == MediumIndex, + err_msg("Bad index: %d", (int)index)); + return &_free_chunks[index]; } @@ -1856,7 +1868,7 @@ } assert((word_size <= chunk->word_size()) || - list_index(chunk->word_size() == HumongousIndex), + (list_index(chunk->word_size()) == HumongousIndex), "Non-humongous variable sized chunk"); if (TraceMetadataChunkAllocation) { size_t list_count; @@ -1883,36 +1895,58 @@ // SpaceManager methods -void SpaceManager::get_initial_chunk_sizes(Metaspace::MetaspaceType type, - size_t* chunk_word_size, - size_t* class_chunk_word_size) { - switch (type) { - case Metaspace::BootMetaspaceType: - *chunk_word_size = Metaspace::first_chunk_word_size(); - *class_chunk_word_size = Metaspace::first_class_chunk_word_size(); - break; - case Metaspace::ROMetaspaceType: - *chunk_word_size = SharedReadOnlySize / wordSize; - *class_chunk_word_size = ClassSpecializedChunk; - break; - case Metaspace::ReadWriteMetaspaceType: - *chunk_word_size = SharedReadWriteSize / wordSize; - *class_chunk_word_size = ClassSpecializedChunk; - break; - case Metaspace::AnonymousMetaspaceType: - case Metaspace::ReflectionMetaspaceType: - *chunk_word_size = SpecializedChunk; - *class_chunk_word_size = ClassSpecializedChunk; - break; - default: - *chunk_word_size = SmallChunk; - *class_chunk_word_size = ClassSmallChunk; - break; +size_t SpaceManager::adjust_initial_chunk_size(size_t requested, bool is_class_space) { + size_t chunk_sizes[] = { + specialized_chunk_size(is_class_space), + small_chunk_size(is_class_space), + medium_chunk_size(is_class_space) + }; + + // Adjust up to one of the fixed chunk sizes ... + for (size_t i = 0; i < ARRAY_SIZE(chunk_sizes); i++) { + if (requested <= chunk_sizes[i]) { + return chunk_sizes[i]; + } } - assert(*chunk_word_size != 0 && *class_chunk_word_size != 0, - err_msg("Initial chunks sizes bad: data " SIZE_FORMAT - " class " SIZE_FORMAT, - *chunk_word_size, *class_chunk_word_size)); + + // ... or return the size as a humongous chunk. + return requested; +} + +size_t SpaceManager::adjust_initial_chunk_size(size_t requested) const { + return adjust_initial_chunk_size(requested, is_class()); +} + +size_t SpaceManager::get_initial_chunk_size(Metaspace::MetaspaceType type) const { + size_t requested; + + if (is_class()) { + switch (type) { + case Metaspace::BootMetaspaceType: requested = Metaspace::first_class_chunk_word_size(); break; + case Metaspace::ROMetaspaceType: requested = ClassSpecializedChunk; break; + case Metaspace::ReadWriteMetaspaceType: requested = ClassSpecializedChunk; break; + case Metaspace::AnonymousMetaspaceType: requested = ClassSpecializedChunk; break; + case Metaspace::ReflectionMetaspaceType: requested = ClassSpecializedChunk; break; + default: requested = ClassSmallChunk; break; + } + } else { + switch (type) { + case Metaspace::BootMetaspaceType: requested = Metaspace::first_chunk_word_size(); break; + case Metaspace::ROMetaspaceType: requested = SharedReadOnlySize / wordSize; break; + case Metaspace::ReadWriteMetaspaceType: requested = SharedReadWriteSize / wordSize; break; + case Metaspace::AnonymousMetaspaceType: requested = SpecializedChunk; break; + case Metaspace::ReflectionMetaspaceType: requested = SpecializedChunk; break; + default: requested = SmallChunk; break; + } + } + + // Adjust to one of the fixed chunk sizes (unless humongous) + const size_t adjusted = adjust_initial_chunk_size(requested); + + assert(adjusted != 0, err_msg("Incorrect initial chunk size. Requested: " + SIZE_FORMAT " adjusted: " SIZE_FORMAT, requested, adjusted)); + + return adjusted; } size_t SpaceManager::sum_free_in_chunks_in_use() const { @@ -2102,8 +2136,8 @@ } // Get another chunk out of the virtual space - size_t grow_chunks_by_words = calc_chunk_size(word_size); - Metachunk* next = get_new_chunk(word_size, grow_chunks_by_words); + size_t chunk_word_size = calc_chunk_size(word_size); + Metachunk* next = get_new_chunk(chunk_word_size); MetaWord* mem = NULL; @@ -2328,22 +2362,18 @@ } ChunkIndex ChunkManager::list_index(size_t size) { - switch (size) { - case SpecializedChunk: - assert(SpecializedChunk == ClassSpecializedChunk, - "Need branch for ClassSpecializedChunk"); - return SpecializedIndex; - case SmallChunk: - case ClassSmallChunk: - return SmallIndex; - case MediumChunk: - case ClassMediumChunk: - return MediumIndex; - default: - assert(size > MediumChunk || size > ClassMediumChunk, - "Not a humongous chunk"); - return HumongousIndex; + if (free_chunks(SpecializedIndex)->size() == size) { + return SpecializedIndex; + } + if (free_chunks(SmallIndex)->size() == size) { + return SmallIndex; } + if (free_chunks(MediumIndex)->size() == size) { + return MediumIndex; + } + + assert(size > free_chunks(MediumIndex)->size(), "Not a humongous chunk"); + return HumongousIndex; } void SpaceManager::deallocate(MetaWord* p, size_t word_size) { @@ -2365,7 +2395,7 @@ // Find the correct list and and set the current // chunk for that list. - ChunkIndex index = ChunkManager::list_index(new_chunk->word_size()); + ChunkIndex index = chunk_manager()->list_index(new_chunk->word_size()); if (index != HumongousIndex) { retire_current_chunk(); @@ -2412,14 +2442,12 @@ } } -Metachunk* SpaceManager::get_new_chunk(size_t word_size, - size_t grow_chunks_by_words) { +Metachunk* SpaceManager::get_new_chunk(size_t chunk_word_size) { // Get a chunk from the chunk freelist - Metachunk* next = chunk_manager()->chunk_freelist_allocate(grow_chunks_by_words); + Metachunk* next = chunk_manager()->chunk_freelist_allocate(chunk_word_size); if (next == NULL) { - next = vs_list()->get_new_chunk(word_size, - grow_chunks_by_words, + next = vs_list()->get_new_chunk(chunk_word_size, medium_chunk_bunch()); } @@ -3125,7 +3153,7 @@ err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), CompressedClassSpaceSize)); assert(using_class_space(), "Must be using class space"); _class_space_list = new VirtualSpaceList(rs); - _chunk_manager_class = new ChunkManager(SpecializedChunk, ClassSmallChunk, ClassMediumChunk); + _chunk_manager_class = new ChunkManager(ClassSpecializedChunk, ClassSmallChunk, ClassMediumChunk); if (!_class_space_list->initialization_succeeded()) { vm_exit_during_initialization("Failed to setup compressed class space virtual space list."); @@ -3326,66 +3354,62 @@ MetaspaceGC::post_initialize(); } -Metachunk* Metaspace::get_initialization_chunk(MetadataType mdtype, - size_t chunk_word_size, - size_t chunk_bunch) { +void Metaspace::initialize_first_chunk(MetaspaceType type, MetadataType mdtype) { + Metachunk* chunk = get_initialization_chunk(type, mdtype); + if (chunk != NULL) { + // Add to this manager's list of chunks in use and current_chunk(). + get_space_manager(mdtype)->add_chunk(chunk, true); + } +} + +Metachunk* Metaspace::get_initialization_chunk(MetaspaceType type, MetadataType mdtype) { + size_t chunk_word_size = get_space_manager(mdtype)->get_initial_chunk_size(type); + // Get a chunk from the chunk freelist Metachunk* chunk = get_chunk_manager(mdtype)->chunk_freelist_allocate(chunk_word_size); - if (chunk != NULL) { - return chunk; + + if (chunk == NULL) { + chunk = get_space_list(mdtype)->get_new_chunk(chunk_word_size, + get_space_manager(mdtype)->medium_chunk_bunch()); + } + + // For dumping shared archive, report error if allocation has failed. + if (DumpSharedSpaces && chunk == NULL) { + report_insufficient_metaspace(MetaspaceAux::committed_bytes() + chunk_word_size * BytesPerWord); } - return get_space_list(mdtype)->get_new_chunk(chunk_word_size, chunk_word_size, chunk_bunch); + return chunk; +} + +void Metaspace::verify_global_initialization() { + assert(space_list() != NULL, "Metadata VirtualSpaceList has not been initialized"); + assert(chunk_manager_metadata() != NULL, "Metadata ChunkManager has not been initialized"); + + if (using_class_space()) { + assert(class_space_list() != NULL, "Class VirtualSpaceList has not been initialized"); + assert(chunk_manager_class() != NULL, "Class ChunkManager has not been initialized"); + } } void Metaspace::initialize(Mutex* lock, MetaspaceType type) { - - assert(space_list() != NULL, - "Metadata VirtualSpaceList has not been initialized"); - assert(chunk_manager_metadata() != NULL, - "Metadata ChunkManager has not been initialized"); - + verify_global_initialization(); + + // Allocate SpaceManager for metadata objects. _vsm = new SpaceManager(NonClassType, lock); - if (_vsm == NULL) { - return; - } - size_t word_size; - size_t class_word_size; - vsm()->get_initial_chunk_sizes(type, &word_size, &class_word_size); if (using_class_space()) { - assert(class_space_list() != NULL, - "Class VirtualSpaceList has not been initialized"); - assert(chunk_manager_class() != NULL, - "Class ChunkManager has not been initialized"); - // Allocate SpaceManager for classes. _class_vsm = new SpaceManager(ClassType, lock); - if (_class_vsm == NULL) { - return; - } } MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); // Allocate chunk for metadata objects - Metachunk* new_chunk = get_initialization_chunk(NonClassType, - word_size, - vsm()->medium_chunk_bunch()); - assert(!DumpSharedSpaces || new_chunk != NULL, "should have enough space for both chunks"); - if (new_chunk != NULL) { - // Add to this manager's list of chunks in use and current_chunk(). - vsm()->add_chunk(new_chunk, true); - } + initialize_first_chunk(type, NonClassType); // Allocate chunk for class metadata objects if (using_class_space()) { - Metachunk* class_chunk = get_initialization_chunk(ClassType, - class_word_size, - class_vsm()->medium_chunk_bunch()); - if (class_chunk != NULL) { - class_vsm()->add_chunk(class_chunk, true); - } + initialize_first_chunk(type, ClassType); } _alloc_record_head = NULL; @@ -3480,6 +3504,16 @@ return capacity_words_slow(mdtype) * BytesPerWord; } +size_t Metaspace::allocated_blocks_bytes() const { + return vsm()->allocated_blocks_bytes() + + (using_class_space() ? class_vsm()->allocated_blocks_bytes() : 0); +} + +size_t Metaspace::allocated_chunks_bytes() const { + return vsm()->allocated_chunks_bytes() + + (using_class_space() ? class_vsm()->allocated_chunks_bytes() : 0); +} + void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) { if (SafepointSynchronize::is_at_safepoint()) { if (DumpSharedSpaces && PrintSharedSpaces) { @@ -3812,7 +3846,7 @@ // vm_allocation_granularity aligned on Windows. size_t large_size = (size_t)(2*256*K + (os::vm_page_size()/BytesPerWord)); large_size += (os::vm_page_size()/BytesPerWord); - vs_list->get_new_chunk(large_size, large_size, 0); + vs_list->get_new_chunk(large_size, 0); } static void test() { @@ -3987,4 +4021,90 @@ TestVirtualSpaceNodeTest::test(); TestVirtualSpaceNodeTest::test_is_available(); } + +// The following test is placed here instead of a gtest / unittest file +// because the ChunkManager class is only available in this file. +class SpaceManagerTest : AllStatic { + friend void SpaceManager_test_adjust_initial_chunk_size(); + + static void test_adjust_initial_chunk_size(bool is_class) { + const size_t smallest = SpaceManager::smallest_chunk_size(is_class); + const size_t normal = SpaceManager::small_chunk_size(is_class); + const size_t medium = SpaceManager::medium_chunk_size(is_class); + +#define test_adjust_initial_chunk_size(value, expected, is_class_value) \ + do { \ + size_t v = value; \ + size_t e = expected; \ + assert(SpaceManager::adjust_initial_chunk_size(v, (is_class_value)) == e, \ + err_msg("Expected: " SIZE_FORMAT " got: " SIZE_FORMAT, e, v)); \ + } while (0) + + // Smallest (specialized) + test_adjust_initial_chunk_size(1, smallest, is_class); + test_adjust_initial_chunk_size(smallest - 1, smallest, is_class); + test_adjust_initial_chunk_size(smallest, smallest, is_class); + + // Small + test_adjust_initial_chunk_size(smallest + 1, normal, is_class); + test_adjust_initial_chunk_size(normal - 1, normal, is_class); + test_adjust_initial_chunk_size(normal, normal, is_class); + + // Medium + test_adjust_initial_chunk_size(normal + 1, medium, is_class); + test_adjust_initial_chunk_size(medium - 1, medium, is_class); + test_adjust_initial_chunk_size(medium, medium, is_class); + + // Humongous + test_adjust_initial_chunk_size(medium + 1, medium + 1, is_class); + +#undef test_adjust_initial_chunk_size + } + + static void test_adjust_initial_chunk_size() { + test_adjust_initial_chunk_size(false); + test_adjust_initial_chunk_size(true); + } +}; + +void SpaceManager_test_adjust_initial_chunk_size() { + SpaceManagerTest::test_adjust_initial_chunk_size(); +} + +// The following test is placed here instead of a gtest / unittest file +// because the ChunkManager class is only available in this file. +void ChunkManager_test_list_index() { + ChunkManager manager(ClassSpecializedChunk, ClassSmallChunk, ClassMediumChunk); + + // Test previous bug where a query for a humongous class metachunk, + // incorrectly matched the non-class medium metachunk size. + { + assert(MediumChunk > ClassMediumChunk, "Precondition for test"); + + ChunkIndex index = manager.list_index(MediumChunk); + + assert(index == HumongousIndex, + err_msg("Requested size is larger than ClassMediumChunk," + " so should return HumongousIndex. Got index: %d", (int)index)); + } + + // Check the specified sizes as well. + { + ChunkIndex index = manager.list_index(ClassSpecializedChunk); + assert(index == SpecializedIndex, err_msg("Wrong index returned. Got index: %d", (int)index)); + } + { + ChunkIndex index = manager.list_index(ClassSmallChunk); + assert(index == SmallIndex, err_msg("Wrong index returned. Got index: %d", (int)index)); + } + { + ChunkIndex index = manager.list_index(ClassMediumChunk); + assert(index == MediumIndex, err_msg("Wrong index returned. Got index: %d", (int)index)); + } + { + ChunkIndex index = manager.list_index(ClassMediumChunk + 1); + assert(index == HumongousIndex, err_msg("Wrong index returned. Got index: %d", (int)index)); + } +} + #endif
--- a/src/share/vm/memory/metaspace.hpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/memory/metaspace.hpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,14 +104,15 @@ }; private: + static void verify_global_initialization(); + void initialize(Mutex* lock, MetaspaceType type); - // Get the first chunk for a Metaspace. Used for + // Initialize the first chunk for a Metaspace. Used for // special cases such as the boot class loader, reflection // class loader and anonymous class loader. - Metachunk* get_initialization_chunk(MetadataType mdtype, - size_t chunk_word_size, - size_t chunk_bunch); + void initialize_first_chunk(MetaspaceType type, MetadataType mdtype); + Metachunk* get_initialization_chunk(MetaspaceType type, MetadataType mdtype); // Align up the word size to the allocation word size static size_t align_word_size_up(size_t); @@ -138,6 +139,10 @@ SpaceManager* _class_vsm; SpaceManager* class_vsm() const { return _class_vsm; } + SpaceManager* get_space_manager(MetadataType mdtype) { + assert(mdtype != MetadataTypeCount, "MetadaTypeCount can't be used as mdtype"); + return mdtype == ClassType ? class_vsm() : vsm(); + } // Allocate space for metadata of type mdtype. This is space // within a Metachunk and is used by @@ -227,6 +232,9 @@ size_t used_bytes_slow(MetadataType mdtype) const; size_t capacity_bytes_slow(MetadataType mdtype) const; + size_t allocated_blocks_bytes() const; + size_t allocated_chunks_bytes() const; + static MetaWord* allocate(ClassLoaderData* loader_data, size_t word_size, bool read_only, MetaspaceObj::Type type, TRAPS); void deallocate(MetaWord* ptr, size_t byte_size, bool is_class);
--- a/src/share/vm/memory/resourceArea.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/memory/resourceArea.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,15 @@ #include "memory/resourceArea.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" +#include "services/memTracker.hpp" + +void ResourceArea::bias_to(MEMFLAGS new_flags) { + if (new_flags != _flags) { + MemTracker::record_arena_free(_flags); + MemTracker::record_new_arena(new_flags); + _flags = new_flags; + } +} //------------------------------ResourceMark----------------------------------- debug_only(int ResourceArea::_warned;) // to suppress multiple warnings
--- a/src/share/vm/memory/resourceArea.hpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/memory/resourceArea.hpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,11 +49,11 @@ debug_only(static int _warned;) // to suppress multiple warnings public: - ResourceArea() : Arena(mtThread) { + ResourceArea(MEMFLAGS flags = mtThread) : Arena(flags) { debug_only(_nesting = 0;) } - ResourceArea(size_t init_size) : Arena(mtThread, init_size) { + ResourceArea(size_t init_size, MEMFLAGS flags = mtThread) : Arena(flags, init_size) { debug_only(_nesting = 0;); } @@ -70,7 +70,11 @@ return (char*)Amalloc(size, alloc_failmode); } - debug_only(int nesting() const { return _nesting; }); + // Bias this resource area to specific memory type + // (by default, ResourceArea is tagged as mtThread, per-thread general purpose storage) + void bias_to(MEMFLAGS flags); + + debug_only(int nesting() const { return _nesting; }) };
--- a/src/share/vm/opto/chaitin.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/opto/chaitin.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -338,8 +338,8 @@ _alternate = 0; _matcher._allocation_started = true; - ResourceArea split_arena; // Arena for Split local resources - ResourceArea live_arena; // Arena for liveness & IFG info + ResourceArea split_arena(mtCompiler); // Arena for Split local resources + ResourceArea live_arena(mtCompiler); // Arena for liveness & IFG info ResourceMark rm(&live_arena); // Need live-ness for the IFG; need the IFG for coalescing. If the
--- a/src/share/vm/opto/loopopts.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/opto/loopopts.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it
--- a/src/share/vm/opto/matcher.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/opto/matcher.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -81,7 +81,7 @@ _register_save_type(register_save_type), _ruleName(ruleName), _allocation_started(false), - _states_arena(Chunk::medium_size), + _states_arena(Chunk::medium_size, mtCompiler), _visited(&_states_arena), _shared(&_states_arena), _dontcare(&_states_arena) {
--- a/src/share/vm/prims/jni.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/prims/jni.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -5095,6 +5095,7 @@ void TestReserveMemorySpecial_test(); void TestVirtualSpace_test(); void TestMetaspaceAux_test(); +void SpaceManager_test_adjust_initial_chunk_size(); void TestMetachunk_test(); void TestVirtualSpaceNode_test(); void TestNewSize_test(); @@ -5107,6 +5108,7 @@ void TestBufferingOopClosure_test(); void TestCodeCacheRemSet_test(); void FreeRegionList_test(); +void ChunkManager_test_list_index(); #endif void execute_internal_vm_tests() { @@ -5139,6 +5141,8 @@ run_unit_test(TestOldFreeSpaceCalculation_test()); run_unit_test(TestG1BiasedArray_test()); run_unit_test(HeapRegionRemSet::test_prt()); + run_unit_test(SpaceManager_test_adjust_initial_chunk_size()); + run_unit_test(ChunkManager_test_list_index()); run_unit_test(TestBufferingOopClosure_test()); run_unit_test(TestCodeCacheRemSet_test()); if (UseG1GC) {
--- a/src/share/vm/runtime/thread.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/runtime/thread.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -3242,6 +3242,9 @@ _scanned_nmethod = NULL; _compiler = NULL; + // Compiler uses resource area for compilation, let's bias it to mtCompiler + resource_area()->bias_to(mtCompiler); + #ifndef PRODUCT _ideal_graph_printer = NULL; #endif
--- a/src/share/vm/runtime/vm_operations.hpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/runtime/vm_operations.hpp Mon Aug 27 16:38:00 2018 +0100 @@ -97,6 +97,7 @@ template(LinuxDllLoad) \ template(RotateGCLog) \ template(WhiteBoxOperation) \ + template(ClassLoaderStatsOperation) \ class VM_Operation: public CHeapObj<mtInternal> { public:
--- a/src/share/vm/services/diagnosticCommand.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/services/diagnosticCommand.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,14 +23,17 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderStats.hpp" #include "gc_implementation/shared/vmGCOperations.hpp" #include "runtime/javaCalls.hpp" +#include "runtime/os.hpp" #include "services/diagnosticArgument.hpp" #include "services/diagnosticCommand.hpp" #include "services/diagnosticFramework.hpp" #include "services/heapDumper.hpp" #include "services/management.hpp" #include "utilities/macros.hpp" +#include "oops/objArrayOop.hpp" PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC @@ -46,9 +49,12 @@ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CommandLineDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintSystemPropertiesDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintVMFlagsDCmd>(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMDynamicLibrariesDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapInfoDCmd>(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<FinalizerInfoDCmd>(full_export, true, false)); #if INCLUDE_SERVICES // Heap dumping/inspection supported DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false)); @@ -56,6 +62,7 @@ #endif // INCLUDE_SERVICES DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false)); // Enhanced JMX Agent Support // These commands won't be exported via the DiagnosticCommandMBean until an @@ -273,6 +280,60 @@ vmSymbols::void_method_signature(), CHECK); } +void HeapInfoDCmd::execute(DCmdSource source, TRAPS) { + Universe::heap()->print_on(output()); +} + +void FinalizerInfoDCmd::execute(DCmdSource source, TRAPS) { + ResourceMark rm; + + + Klass* k = SystemDictionary::resolve_or_null( + vmSymbols::finalizer_histogram_klass(), THREAD); + assert(k != NULL, "FinalizerHistogram class is not accessible"); + + instanceKlassHandle klass(THREAD, k); + JavaValue result(T_ARRAY); + + // We are calling lang.ref.FinalizerHistogram.getFinalizerHistogram() method + // and expect it to return array of FinalizerHistogramEntry as Object[] + + JavaCalls::call_static(&result, klass, + vmSymbols::get_finalizer_histogram_name(), + vmSymbols::void_finalizer_histogram_entry_array_signature(), CHECK); + + objArrayOop result_oop = (objArrayOop) result.get_jobject(); + if (result_oop->length() == 0) { + output()->print_cr("No instances waiting for finalization found"); + return; + } + + oop foop = result_oop->obj_at(0); + InstanceKlass* ik = InstanceKlass::cast(foop->klass()); + + fieldDescriptor count_fd, name_fd; + + Klass* count_res = ik->find_field( + vmSymbols::finalizer_histogram_entry_count_field(), vmSymbols::int_signature(), &count_fd); + + Klass* name_res = ik->find_field( + vmSymbols::finalizer_histogram_entry_name_field(), vmSymbols::string_signature(), &name_fd); + + assert(count_res != NULL && name_res != NULL, "Unexpected layout of FinalizerHistogramEntry"); + + output()->print_cr("Unreachable instances waiting for finalization"); + output()->print_cr("#instances class name"); + output()->print_cr("-----------------------"); + + for (int i = 0; i < result_oop->length(); ++i) { + oop element_oop = result_oop->obj_at(i); + oop str_oop = element_oop->obj_field(name_fd.offset()); + char *name = java_lang_String::as_utf8_string(str_oop); + int count = element_oop->int_field(count_fd.offset()); + output()->print_cr("%10d %s", count, name); + } +} + #if INCLUDE_SERVICES // Heap dumping/inspection supported HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), @@ -619,8 +680,7 @@ } JMXStartLocalDCmd::JMXStartLocalDCmd(outputStream *output, bool heap_allocated) : - DCmd(output, heap_allocated) -{ + DCmd(output, heap_allocated) { // do nothing } @@ -641,7 +701,6 @@ JavaCalls::call_static(&result, ik, vmSymbols::startLocalAgent_name(), vmSymbols::void_method_signature(), CHECK); } - void JMXStopRemoteDCmd::execute(DCmdSource source, TRAPS) { ResourceMark rm(THREAD); HandleMark hm(THREAD); @@ -659,6 +718,16 @@ JavaCalls::call_static(&result, ik, vmSymbols::stopRemoteAgent_name(), vmSymbols::void_method_signature(), CHECK); } +VMDynamicLibrariesDCmd::VMDynamicLibrariesDCmd(outputStream *output, bool heap_allocated) : + DCmd(output, heap_allocated) { + // do nothing +} + +void VMDynamicLibrariesDCmd::execute(DCmdSource source, TRAPS) { + os::print_dll_info(output()); + output()->cr(); +} + void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) { if (UseGCLogFileRotation) { VM_RotateGCLog rotateop(output());
--- a/src/share/vm/services/diagnosticCommand.hpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/services/diagnosticCommand.hpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,29 @@ virtual void execute(DCmdSource source, TRAPS); }; +class VMDynamicLibrariesDCmd : public DCmd { +public: + VMDynamicLibrariesDCmd(outputStream* output, bool heap); + static const char* name() { + return "VM.dynlibs"; + } + static const char* description() { + return "Print loaded dynamic libraries."; + } + static const char* impact() { + return "Low"; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments() { + return 0; + }; + virtual void execute(DCmdSource source, TRAPS); +}; + class VMUptimeDCmd : public DCmdWithParser { protected: DCmdArgument<bool> _date; @@ -176,6 +199,46 @@ virtual void execute(DCmdSource source, TRAPS); }; +class HeapInfoDCmd : public DCmd { +public: + HeapInfoDCmd(outputStream* output, bool heap) : DCmd(output, heap) { } + static const char* name() { return "GC.heap_info"; } + static const char* description() { + return "Provide generic Java heap information."; + } + static const char* impact() { + return "Medium"; + } + static int num_arguments() { return 0; } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + + virtual void execute(DCmdSource source, TRAPS); +}; + +class FinalizerInfoDCmd : public DCmd { +public: + FinalizerInfoDCmd(outputStream* output, bool heap) : DCmd(output, heap) { } + static const char* name() { return "GC.finalizer_info"; } + static const char* description() { + return "Provide information about Java finalization queue."; + } + static const char* impact() { + return "Medium"; + } + static int num_arguments() { return 0; } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + + virtual void execute(DCmdSource source, TRAPS); +}; + #if INCLUDE_SERVICES // Heap dumping supported // See also: dump_heap in attachListener.cpp class HeapDumpDCmd : public DCmdWithParser {
--- a/src/share/vm/services/mallocSiteTable.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/services/mallocSiteTable.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,7 +97,7 @@ // Instantiate hash entry for hashtable entry allocation callsite MallocSiteHashtableEntry* entry = ::new ((void*)_hash_entry_allocation_site) - MallocSiteHashtableEntry(*stack); + MallocSiteHashtableEntry(*stack, mtNMT); // Add the allocation site to hashtable. int index = hash_to_index(stack->hash()); @@ -134,7 +134,8 @@ * Under any of above circumstances, caller should handle the situation. */ MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, size_t* bucket_idx, - size_t* pos_idx) { + size_t* pos_idx, MEMFLAGS flags) { + assert(flags != mtNone, "Should have a real memory type"); int index = hash_to_index(key.hash()); assert(index >= 0, "Negative index"); *bucket_idx = (size_t)index; @@ -142,7 +143,7 @@ // First entry for this hash bucket if (_table[index] == NULL) { - MallocSiteHashtableEntry* entry = new_entry(key); + MallocSiteHashtableEntry* entry = new_entry(key, flags); // OOM check if (entry == NULL) return NULL; @@ -157,13 +158,12 @@ MallocSiteHashtableEntry* head = _table[index]; while (head != NULL && (*pos_idx) <= MAX_BUCKET_LENGTH) { MallocSite* site = head->data(); - if (site->equals(key)) { - // found matched entry + if (site->flags() == flags && site->equals(key)) { return head->data(); } if (head->next() == NULL && (*pos_idx) < MAX_BUCKET_LENGTH) { - MallocSiteHashtableEntry* entry = new_entry(key); + MallocSiteHashtableEntry* entry = new_entry(key, flags); // OOM check if (entry == NULL) return NULL; if (head->atomic_insert(entry)) { @@ -192,10 +192,10 @@ // Allocates MallocSiteHashtableEntry object. Special call stack // (pre-installed allocation site) has to be used to avoid infinite // recursion. -MallocSiteHashtableEntry* MallocSiteTable::new_entry(const NativeCallStack& key) { +MallocSiteHashtableEntry* MallocSiteTable::new_entry(const NativeCallStack& key, MEMFLAGS flags) { void* p = AllocateHeap(sizeof(MallocSiteHashtableEntry), mtNMT, *hash_entry_allocation_stack(), AllocFailStrategy::RETURN_NULL); - return ::new (p) MallocSiteHashtableEntry(key); + return ::new (p) MallocSiteHashtableEntry(key, flags); } void MallocSiteTable::reset() {
--- a/src/share/vm/services/mallocSiteTable.hpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/services/mallocSiteTable.hpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,12 +37,16 @@ // MallocSite represents a code path that eventually calls // os::malloc() to allocate memory class MallocSite : public AllocationSite<MemoryCounter> { + private: + MEMFLAGS _flags; + public: MallocSite() : - AllocationSite<MemoryCounter>(NativeCallStack::EMPTY_STACK) { } + AllocationSite<MemoryCounter>(NativeCallStack::EMPTY_STACK), _flags(mtNone) {} - MallocSite(const NativeCallStack& stack) : - AllocationSite<MemoryCounter>(stack) { } + MallocSite(const NativeCallStack& stack, MEMFLAGS flags) : + AllocationSite<MemoryCounter>(stack), _flags(flags) {} + void allocate(size_t size) { data()->allocate(size); } void deallocate(size_t size) { data()->deallocate(size); } @@ -51,6 +55,7 @@ size_t size() const { return peek()->size(); } // The number of calls were made size_t count() const { return peek()->count(); } + MEMFLAGS flags() const { return (MEMFLAGS)_flags; } }; // Malloc site hashtable entry @@ -62,8 +67,10 @@ public: MallocSiteHashtableEntry() : _next(NULL) { } - MallocSiteHashtableEntry(NativeCallStack stack): - _malloc_site(stack), _next(NULL) { } + MallocSiteHashtableEntry(NativeCallStack stack, MEMFLAGS flags): + _malloc_site(stack, flags), _next(NULL) { + assert(flags != mtNone, "Expect a real memory type"); + } inline const MallocSiteHashtableEntry* next() const { return _next; @@ -198,11 +205,11 @@ // 1. out of memory // 2. overflow hash bucket static inline bool allocation_at(const NativeCallStack& stack, size_t size, - size_t* bucket_idx, size_t* pos_idx) { + size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) { AccessLock locker(&_access_count); if (locker.sharedLock()) { NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);) - MallocSite* site = lookup_or_add(stack, bucket_idx, pos_idx); + MallocSite* site = lookup_or_add(stack, bucket_idx, pos_idx, flags); if (site != NULL) site->allocate(size); return site != NULL; } @@ -228,13 +235,13 @@ static bool walk_malloc_site(MallocSiteWalker* walker); private: - static MallocSiteHashtableEntry* new_entry(const NativeCallStack& key); + static MallocSiteHashtableEntry* new_entry(const NativeCallStack& key, MEMFLAGS flags); static void reset(); // Delete a bucket linked list static void delete_linked_list(MallocSiteHashtableEntry* head); - static MallocSite* lookup_or_add(const NativeCallStack& key, size_t* bucket_idx, size_t* pos_idx); + static MallocSite* lookup_or_add(const NativeCallStack& key, size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags); static MallocSite* malloc_site(size_t bucket_idx, size_t pos_idx); static bool walk(MallocSiteWalker* walker);
--- a/src/share/vm/services/mallocTracker.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/services/mallocTracker.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,8 +78,8 @@ } bool MallocHeader::record_malloc_site(const NativeCallStack& stack, size_t size, - size_t* bucket_idx, size_t* pos_idx) const { - bool ret = MallocSiteTable::allocation_at(stack, size, bucket_idx, pos_idx); + size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) const { + bool ret = MallocSiteTable::allocation_at(stack, size, bucket_idx, pos_idx, flags); // Something went wrong, could be OOM or overflow malloc site table. // We want to keep tracking data under OOM circumstance, so transition to
--- a/src/share/vm/services/mallocTracker.hpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/services/mallocTracker.hpp Mon Aug 27 16:38:00 2018 +0100 @@ -268,7 +268,7 @@ if (level == NMT_detail) { size_t bucket_idx; size_t pos_idx; - if (record_malloc_site(stack, size, &bucket_idx, &pos_idx)) { + if (record_malloc_site(stack, size, &bucket_idx, &pos_idx, flags)) { assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE, "Overflow bucket index"); assert(pos_idx <= MAX_BUCKET_LENGTH, "Overflow bucket position index"); _bucket_idx = bucket_idx; @@ -292,7 +292,7 @@ _size = size; } bool record_malloc_site(const NativeCallStack& stack, size_t size, - size_t* bucket_idx, size_t* pos_idx) const; + size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) const; };
--- a/src/share/vm/services/memBaseline.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/services/memBaseline.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,6 +59,15 @@ return s1.call_stack()->compare(*s2.call_stack()); } +// Sort into allocation site addresses and memory type order for baseline comparison +int compare_malloc_site_and_type(const MallocSite& s1, const MallocSite& s2) { + int res = compare_malloc_site(s1, s2); + if (res == 0) { + res = (int)(s1.flags() - s2.flags()); + } + + return res; +} int compare_virtual_memory_site(const VirtualMemoryAllocationSite& s1, const VirtualMemoryAllocationSite& s2) { @@ -225,6 +234,9 @@ case by_site: malloc_sites_to_allocation_site_order(); break; + case by_site_and_type: + malloc_sites_to_allocation_site_and_type_order(); + break; case by_address: default: ShouldNotReachHere(); @@ -263,7 +275,7 @@ } void MemBaseline::malloc_sites_to_allocation_site_order() { - if (_malloc_sites_order != by_site) { + if (_malloc_sites_order != by_site && _malloc_sites_order != by_site_and_type) { SortedLinkedList<MallocSite, compare_malloc_site> tmp; // Add malloc sites to sorted linked list to sort into site (address) order tmp.move(&_malloc_sites); @@ -273,6 +285,17 @@ } } +void MemBaseline::malloc_sites_to_allocation_site_and_type_order() { + if (_malloc_sites_order != by_site_and_type) { + SortedLinkedList<MallocSite, compare_malloc_site_and_type> tmp; + // Add malloc sites to sorted linked list to sort into site (address) order + tmp.move(&_malloc_sites); + _malloc_sites.set_head(tmp.head()); + tmp.set_head(NULL); + _malloc_sites_order = by_site_and_type; + } +} + void MemBaseline::virtual_memory_sites_to_size_order() { if (_virtual_memory_sites_order != by_size) { SortedLinkedList<VirtualMemoryAllocationSite, compare_virtual_memory_size> tmp;
--- a/src/share/vm/services/memBaseline.hpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/services/memBaseline.hpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,9 +55,10 @@ }; enum SortingOrder { - by_address, // by memory address - by_size, // by memory size - by_site // by call site where the memory is allocated from + by_address, // by memory address + by_size, // by memory size + by_site, // by call site where the memory is allocated from + by_site_and_type // by call site and memory type }; private: @@ -188,6 +189,8 @@ void malloc_sites_to_size_order(); // Sort allocation sites in call site address order void malloc_sites_to_allocation_site_order(); + // Sort allocation sites in call site address and memory type order + void malloc_sites_to_allocation_site_and_type_order(); // Sort allocation sites in reserved size order void virtual_memory_sites_to_size_order();
--- a/src/share/vm/services/memReporter.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/services/memReporter.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,11 +43,16 @@ amount_in_current_scale(reserved), scale, amount_in_current_scale(committed), scale); } -void MemReporterBase::print_malloc(size_t amount, size_t count) const { +void MemReporterBase::print_malloc(size_t amount, size_t count, MEMFLAGS flag) const { const char* scale = current_scale(); outputStream* out = output(); - out->print("(malloc=" SIZE_FORMAT "%s", - amount_in_current_scale(amount), scale); + if (flag != mtNone) { + out->print("(malloc=" SIZE_FORMAT "%s type=%s", + amount_in_current_scale(amount), scale, NMTUtil::flag_to_name(flag)); + } else { + out->print("(malloc=" SIZE_FORMAT "%s", + amount_in_current_scale(amount), scale); + } if (count > 0) { out->print(" #" SIZE_FORMAT "", count); @@ -200,7 +205,10 @@ const NativeCallStack* stack = malloc_site->call_stack(); stack->print_on(out); out->print("%29s", " "); - print_malloc(malloc_site->size(), malloc_site->count()); + MEMFLAGS flag = malloc_site->flags(); + assert((flag >= 0 && flag < (int)mt_number_of_types) && flag != mtNone, + "Must have a valid memory type"); + print_malloc(malloc_site->size(), malloc_site->count(),flag); out->print_cr("\n"); } } @@ -304,11 +312,16 @@ } void MemSummaryDiffReporter::print_malloc_diff(size_t current_amount, size_t current_count, - size_t early_amount, size_t early_count) const { + size_t early_amount, size_t early_count, MEMFLAGS flags) const { const char* scale = current_scale(); outputStream* out = output(); out->print("malloc=" SIZE_FORMAT "%s", amount_in_current_scale(current_amount), scale); + // Report type only if it is valid + if (flags != mtNone) { + out->print(" type=%s", NMTUtil::flag_to_name(flags)); + } + long amount_diff = diff_in_current_scale(current_amount, early_amount); if (amount_diff != 0) { out->print(" %+ld%s", amount_diff, scale); @@ -437,7 +450,7 @@ diff_in_current_scale(current_malloc_amount, early_malloc_amount) != 0) { out->print("%28s(", " "); print_malloc_diff(current_malloc_amount, (flag == mtChunk) ? 0 : current_malloc->malloc_count(), - early_malloc_amount, early_malloc->malloc_count()); + early_malloc_amount, early_malloc->malloc_count(), mtNone); out->print_cr(")"); } @@ -485,8 +498,8 @@ } void MemDetailDiffReporter::diff_malloc_sites() const { - MallocSiteIterator early_itr = _early_baseline.malloc_sites(MemBaseline::by_site); - MallocSiteIterator current_itr = _current_baseline.malloc_sites(MemBaseline::by_site); + MallocSiteIterator early_itr = _early_baseline.malloc_sites(MemBaseline::by_site_and_type); + MallocSiteIterator current_itr = _current_baseline.malloc_sites(MemBaseline::by_site_and_type); const MallocSite* early_site = early_itr.next(); const MallocSite* current_site = current_itr.next(); @@ -549,22 +562,23 @@ void MemDetailDiffReporter::new_malloc_site(const MallocSite* malloc_site) const { diff_malloc_site(malloc_site->call_stack(), malloc_site->size(), malloc_site->count(), - 0, 0); + 0, 0, malloc_site->flags()); } void MemDetailDiffReporter::old_malloc_site(const MallocSite* malloc_site) const { diff_malloc_site(malloc_site->call_stack(), 0, 0, malloc_site->size(), - malloc_site->count()); + malloc_site->count(), malloc_site->flags()); } void MemDetailDiffReporter::diff_malloc_site(const MallocSite* early, const MallocSite* current) const { + assert(early->flags() == current->flags(), "Must be the same memory type"); diff_malloc_site(current->call_stack(), current->size(), current->count(), - early->size(), early->count()); + early->size(), early->count(), early->flags()); } void MemDetailDiffReporter::diff_malloc_site(const NativeCallStack* stack, size_t current_size, - size_t current_count, size_t early_size, size_t early_count) const { + size_t current_count, size_t early_size, size_t early_count, MEMFLAGS flags) const { outputStream* out = output(); assert(stack != NULL, "NULL stack"); @@ -576,7 +590,7 @@ stack->print_on(out); out->print("%28s (", " "); print_malloc_diff(current_size, current_count, - early_size, early_count); + early_size, early_count, flags); out->print_cr(")\n"); }
--- a/src/share/vm/services/memReporter.hpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/services/memReporter.hpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,7 +76,7 @@ // Print summary total, malloc and virtual memory void print_total(size_t reserved, size_t committed) const; - void print_malloc(size_t amount, size_t count) const; + void print_malloc(size_t amount, size_t count, MEMFLAGS flag = mtNone) const; void print_virtual_memory(size_t reserved, size_t committed) const; void print_malloc_line(size_t amount, size_t count) const; @@ -174,7 +174,7 @@ protected: void print_malloc_diff(size_t current_amount, size_t current_count, - size_t early_amount, size_t early_count) const; + size_t early_amount, size_t early_count, MEMFLAGS flags) const; void print_virtual_memory_diff(size_t current_reserved, size_t current_committed, size_t early_reserved, size_t early_committed) const; void print_arena_diff(size_t current_amount, size_t current_count, @@ -216,7 +216,7 @@ const VirtualMemoryAllocationSite* current) const; void diff_malloc_site(const NativeCallStack* stack, size_t current_size, - size_t currrent_count, size_t early_size, size_t early_count) const; + size_t currrent_count, size_t early_size, size_t early_count, MEMFLAGS flags) const; void diff_virtual_memory_site(const NativeCallStack* stack, size_t current_reserved, size_t current_committed, size_t early_reserved, size_t early_committed) const; };
--- a/src/share/vm/utilities/debug.cpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/utilities/debug.cpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -315,6 +315,14 @@ } } +void report_insufficient_metaspace(size_t required_size) { + warning("\nThe MaxMetaspaceSize of " SIZE_FORMAT " bytes is not large enough.\n" + "Either don't specify the -XX:MaxMetaspaceSize=<size>\n" + "or increase the size to at least " SIZE_FORMAT ".\n", + MaxMetaspaceSize, required_size); + exit(2); +} + static bool error_reported = false; // call this when the VM is dying--it might loosen some asserts
--- a/src/share/vm/utilities/debug.hpp Sun Aug 19 04:29:57 2018 +0100 +++ b/src/share/vm/utilities/debug.hpp Mon Aug 27 16:38:00 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -222,6 +222,7 @@ void report_should_not_reach_here(const char* file, int line); void report_unimplemented(const char* file, int line); void report_untested(const char* file, int line, const char* message); +void report_insufficient_metaspace(size_t required_size); void warning(const char* format, ...) ATTRIBUTE_PRINTF(1, 2);
--- a/test/TEST.groups Sun Aug 19 04:29:57 2018 +0100 +++ b/test/TEST.groups Mon Aug 27 16:38:00 2018 +0100 @@ -96,6 +96,7 @@ runtime/XCheckJniJsig/XCheckJSig.java \ serviceability/attach/AttachWithStalePidFile.java \ serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java \ + serviceability/dcmd/DynLibDcmdTest.java \ testlibrary_tests/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/serviceability/dcmd/ClassLoaderStatsTest.java Mon Aug 27 16:38:00 2018 +0100 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * + * @build ClassLoaderStatsTest DcmdUtil + * @run main ClassLoaderStatsTest + */ + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.StringReader; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ClassLoaderStatsTest { + + // ClassLoader Parent CLD* Classes ChunkSz BlockSz Type + // 0x00000007c0215928 0x0000000000000000 0x0000000000000000 0 0 0 org.eclipse.osgi.baseadaptor.BaseAdaptor$1 + // 0x00000007c0009868 0x0000000000000000 0x00007fc52aebcc80 1 6144 3768 sun.reflect.DelegatingClassLoader + // 0x00000007c0009868 0x0000000000000000 0x00007fc52b8916d0 1 6144 3688 sun.reflect.DelegatingClassLoader + // 0x00000007c0009868 0x00000007c0038ba8 0x00007fc52afb8760 1 6144 3688 sun.reflect.DelegatingClassLoader + // 0x00000007c0009868 0x0000000000000000 0x00007fc52afbb1a0 1 6144 3688 sun.reflect.DelegatingClassLoader + // 0x0000000000000000 0x0000000000000000 0x00007fc523416070 5019 30060544 29956216 <boot classloader> + // 455 1210368 672848 + unsafe anonymous classes + // 0x00000007c016b5c8 0x00000007c0038ba8 0x00007fc52a995000 5 8192 5864 org.netbeans.StandardModule$OneModuleClassLoader + // 0x00000007c0009868 0x00000007c016b5c8 0x00007fc52ac13640 1 6144 3896 sun.reflect.DelegatingClassLoader + // ... + + static Pattern clLine = Pattern.compile("0x\\p{XDigit}*\\s*0x\\p{XDigit}*\\s*0x\\p{XDigit}*\\s*(\\d*)\\s*(\\d*)\\s*(\\d*)\\s*(.*)"); + static Pattern anonLine = Pattern.compile("\\s*(\\d*)\\s*(\\d*)\\s*(\\d*)\\s*.*"); + + public static DummyClassLoader dummyloader; + + public static void main(String arg[]) throws Exception { + + // create a classloader and load our special class + dummyloader = new DummyClassLoader(); + Class<?> c = Class.forName("TestClass", true, dummyloader); + if (c.getClassLoader() != dummyloader) { + throw new RuntimeException("TestClass defined by wrong classloader: " + c.getClassLoader()); + } + + String result = DcmdUtil.executeDcmd("VM.classloader_stats"); + BufferedReader r = new BufferedReader(new StringReader(result)); + String line; + while((line = r.readLine()) != null) { + Matcher m = clLine.matcher(line); + if (m.matches()) { + // verify that DummyClassLoader has loaded 1 class and 1 anonymous class + if (m.group(4).equals("ClassLoaderStatsTest$DummyClassLoader")) { + System.out.println("line: " + line); + if (!m.group(1).equals("1")) { + throw new Exception("Should have loaded 1 class: " + line); + } + checkPositiveInt(m.group(2)); + checkPositiveInt(m.group(3)); + + String next = r.readLine(); + System.out.println("next: " + next); + Matcher m1 = anonLine.matcher(next); + m1.matches(); + if (!m1.group(1).equals("1")) { + throw new Exception("Should have loaded 1 anonymous class, but found : " + m1.group(1)); + } + checkPositiveInt(m1.group(2)); + checkPositiveInt(m1.group(3)); + } + } + } + } + + private static void checkPositiveInt(String s) throws Exception { + if (Integer.parseInt(s) <= 0) { + throw new Exception("Value should have been > 0: " + s); + } + } + + public static class DummyClassLoader extends ClassLoader { + + public static final String CLASS_NAME = "TestClass"; + + static ByteBuffer readClassFile(String name) + { + File f = new File(System.getProperty("test.classes", "."), + name); + try (FileInputStream fin = new FileInputStream(f); + FileChannel fc = fin.getChannel()) + { + return fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); + } catch (IOException e) { + throw new RuntimeException("Can't open file: " + name, e); + } + } + + protected Class<?> loadClass(String name, boolean resolve) + throws ClassNotFoundException + { + Class<?> c; + if (!"TestClass".equals(name)) { + c = super.loadClass(name, resolve); + } else { + // should not delegate to the system class loader + c = findClass(name); + if (resolve) { + resolveClass(c); + } + } + return c; + } + + protected Class<?> findClass(String name) + throws ClassNotFoundException + { + if (!"TestClass".equals(name)) { + throw new ClassNotFoundException("Unexpected class: " + name); + } + return defineClass(name, readClassFile(name + ".class"), null); + } + } /* DummyClassLoader */ + +} + +class TestClass { + static { + // force creation of anonymous class (for the lambdaform) + Runnable r = () -> System.out.println("Hello"); + r.run(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/serviceability/dcmd/DcmdUtil.java Mon Aug 27 16:38:00 2018 +0100 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import sun.management.ManagementFactoryHelper; + +import com.sun.management.DiagnosticCommandMBean; + +public class DcmdUtil +{ + public static String executeDcmd(String cmd, String ... args) { + DiagnosticCommandMBean dcmd = ManagementFactoryHelper.getDiagnosticCommandMBean(); + Object[] dcmdArgs = {args}; + String[] signature = {String[].class.getName()}; + + try { + System.out.print("> " + cmd + " "); + for (String s : args) { + System.out.print(s + " "); + } + System.out.println(":"); + String result = (String) dcmd.invoke(transform(cmd), dcmdArgs, signature); + System.out.println(result); + return result; + } catch(Exception ex) { + ex.printStackTrace(); + } + return null; + } + + private static String transform(String name) { + StringBuilder sb = new StringBuilder(); + boolean toLower = true; + boolean toUpper = false; + for (int i = 0; i < name.length(); i++) { + char c = name.charAt(i); + if (c == '.' || c == '_') { + toLower = false; + toUpper = true; + } else { + if (toUpper) { + toUpper = false; + sb.append(Character.toUpperCase(c)); + } else if(toLower) { + sb.append(Character.toLowerCase(c)); + } else { + sb.append(c); + } + } + } + return sb.toString(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/serviceability/dcmd/DynLibDcmdTest.java Mon Aug 27 16:38:00 2018 +0100 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.HashSet; +import java.util.Set; +import com.oracle.java.testlibrary.Platform; + +/* + * @test + * @summary Test of VM.dynlib diagnostic command via MBean + * @library /testlibrary + * @compile DcmdUtil.java + * @run main DynLibDcmdTest + */ + +public class DynLibDcmdTest { + + public static void main(String[] args) throws Exception { + String result = DcmdUtil.executeDcmd("VM.dynlibs"); + + String osDependentBaseString = null; + if (Platform.isSolaris()) { + osDependentBaseString = "lib%s.so"; + } else if (Platform.isWindows()) { + osDependentBaseString = "%s.dll"; + } else if (Platform.isOSX()) { + osDependentBaseString = "lib%s.dylib"; + } else if (Platform.isLinux()) { + osDependentBaseString = "lib%s.so"; + } + + if (osDependentBaseString == null) { + throw new Exception("Unsupported OS"); + } + + Set<String> expectedContent = new HashSet<>(); + expectedContent.add(String.format(osDependentBaseString, "jvm")); + expectedContent.add(String.format(osDependentBaseString, "java")); + expectedContent.add(String.format(osDependentBaseString, "management")); + + for(String expected : expectedContent) { + if (!result.contains(expected)) { + throw new Exception("Dynamic library list output did not contain the expected string: '" + expected + "'"); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/serviceability/dcmd/gc/FinalizerInfoTest.java Mon Aug 27 16:38:00 2018 +0100 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.oracle.java.testlibrary.JDKToolFinder; +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/* + * @test + * @summary + * @library /testlibrary + * @run main FinalizerInfoTest + */ +public class FinalizerInfoTest { + static ReentrantLock lock = new ReentrantLock(); + static volatile int wasInitialized = 0; + static volatile int wasTrapped = 0; + static final String cmd = "GC.finalizer_info"; + static final int objectsCount = 1000; + + class MyObject { + public MyObject() { + // Make sure object allocation/deallocation is not optimized out + wasInitialized += 1; + } + + protected void finalize() { + // Trap the object in a finalization queue + wasTrapped += 1; + lock.lock(); + } + } + + void run() throws Exception { + try { + lock.lock(); + for(int i = 0; i < objectsCount; ++i) { + new MyObject(); + } + System.out.println("Objects initialized: " + objectsCount); + System.gc(); + + while(wasTrapped < 1) { + // Waiting for gc thread. + } + + + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, cmd}); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("MyObject"); + } finally { + lock.unlock(); + } + } + + public static void main(String[] args) throws Exception { + new FinalizerInfoTest().run(); + } + + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/serviceability/dcmd/gc/HeapInfoTest.java Mon Aug 27 16:38:00 2018 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.oracle.java.testlibrary.JDKToolFinder; +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +/* + * @test + * @summary Test of diagnostic command GC.heap_info + * @library /testlibrary + * @run main HeapInfoTest + */ +public class HeapInfoTest { + + public static void main(String[] args) throws Exception { + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "GC.heap_info"}); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Metaspace"); + } +} +