8079408: Reimplement TraceClassLoading, TraceClassUnloading, and TraceClassLoaderData with Unified Logging
TraceClassLoading, TraceClassUnloading, and TraceClassLoaderData have been reimplemented using Unified logging. Co-authored-by: Ioi Lam <ioi.lam@oracle.com> Reviewed-by: iklam, coleenp, dholmes, jiangli, hseigel, rprotacio
This commit is contained in:
parent
828a52c262
commit
9cab990401
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2015, 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
|
||||
@ -34,6 +34,7 @@
|
||||
#include "classfile/verifier.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "gc/shared/gcLocker.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
@ -5347,30 +5348,12 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) {
|
||||
ClassLoadingService::notify_class_loaded(ik, false /* not shared class */);
|
||||
|
||||
if (!is_internal()) {
|
||||
if (TraceClassLoading) {
|
||||
ResourceMark rm;
|
||||
// print in a single call to reduce interleaving of output
|
||||
if (_stream->source() != NULL) {
|
||||
tty->print("[Loaded %s from %s]\n",
|
||||
ik->external_name(),
|
||||
_stream->source());
|
||||
} else if (_loader_data->class_loader() == NULL) {
|
||||
const Klass* const caller =
|
||||
THREAD->is_Java_thread()
|
||||
? ((JavaThread*)THREAD)->security_get_caller_class(1)
|
||||
: NULL;
|
||||
// caller can be NULL, for example, during a JVMTI VM_Init hook
|
||||
if (caller != NULL) {
|
||||
tty->print("[Loaded %s by instance of %s]\n",
|
||||
ik->external_name(),
|
||||
caller->external_name());
|
||||
} else {
|
||||
tty->print("[Loaded %s]\n", ik->external_name());
|
||||
}
|
||||
} else {
|
||||
tty->print("[Loaded %s from %s]\n", ik->external_name(),
|
||||
_loader_data->class_loader()->klass()->external_name());
|
||||
}
|
||||
if (log_is_enabled(Info, classload)) {
|
||||
ik->print_loading_log(LogLevel::Info, _loader_data, _stream);
|
||||
}
|
||||
// No 'else' here as logging levels are not mutually exclusive
|
||||
if (log_is_enabled(Debug, classload)) {
|
||||
ik->print_loading_log(LogLevel::Debug, _loader_data, _stream);
|
||||
}
|
||||
|
||||
if (log_is_enabled(Info, classresolve)) {
|
||||
|
@ -578,15 +578,14 @@ ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const str
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TraceClassLoading || TraceClassPaths) {
|
||||
if (TraceClassPaths) {
|
||||
tty->print_cr("[Opened %s]", path);
|
||||
}
|
||||
log_info(classload)("opened: %s", path);
|
||||
} else {
|
||||
// Directory
|
||||
new_entry = new ClassPathDirEntry(path);
|
||||
if (TraceClassLoading) {
|
||||
tty->print_cr("[Path %s]", path);
|
||||
}
|
||||
log_info(classload)("path: %s", path);
|
||||
}
|
||||
return new_entry;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016, 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
|
||||
@ -54,12 +54,14 @@
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "gc/shared/gcLocker.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "oops/objArrayOop.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/atomic.inline.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/jniHandles.hpp"
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
@ -286,9 +288,9 @@ void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) {
|
||||
_klasses = k;
|
||||
}
|
||||
|
||||
if (publicize && TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
|
||||
if (publicize && k->class_loader_data() != NULL) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("[TraceClassLoaderData] Adding k: " PTR_FORMAT " %s to CLD: "
|
||||
log_trace(classloaderdata)("Adding k: " PTR_FORMAT " %s to CLD: "
|
||||
PTR_FORMAT " loader: " PTR_FORMAT " %s",
|
||||
p2i(k),
|
||||
k->external_name(),
|
||||
@ -326,15 +328,16 @@ void ClassLoaderData::unload() {
|
||||
// Tell serviceability tools these classes are unloading
|
||||
classes_do(InstanceKlass::notify_unload_class);
|
||||
|
||||
if (TraceClassLoaderData) {
|
||||
if (log_is_enabled(Debug, classloaderdata)) {
|
||||
ResourceMark rm;
|
||||
tty->print("[ClassLoaderData: unload loader data " INTPTR_FORMAT, p2i(this));
|
||||
tty->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)class_loader()),
|
||||
outputStream* log = LogHandle(classloaderdata)::debug_stream();
|
||||
log->print(": unload loader data " INTPTR_FORMAT, p2i(this));
|
||||
log->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)class_loader()),
|
||||
loader_name());
|
||||
if (is_anonymous()) {
|
||||
tty->print(" for anonymous class " INTPTR_FORMAT " ", p2i(_klasses));
|
||||
log->print(" for anonymous class " INTPTR_FORMAT " ", p2i(_klasses));
|
||||
}
|
||||
tty->print_cr("]");
|
||||
log->cr();
|
||||
}
|
||||
}
|
||||
|
||||
@ -408,13 +411,13 @@ Metaspace* ClassLoaderData::metaspace_non_null() {
|
||||
assert (class_loader() == NULL, "Must be");
|
||||
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::BootMetaspaceType));
|
||||
} else if (is_anonymous()) {
|
||||
if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
|
||||
tty->print_cr("is_anonymous: %s", class_loader()->klass()->internal_name());
|
||||
if (class_loader() != NULL) {
|
||||
log_trace(classloaderdata)("is_anonymous: %s", class_loader()->klass()->internal_name());
|
||||
}
|
||||
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::AnonymousMetaspaceType));
|
||||
} else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
|
||||
if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
|
||||
tty->print_cr("is_reflection: %s", class_loader()->klass()->internal_name());
|
||||
if (class_loader() != NULL) {
|
||||
log_trace(classloaderdata)("is_reflection: %s", class_loader()->klass()->internal_name());
|
||||
}
|
||||
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType));
|
||||
} else {
|
||||
@ -601,21 +604,47 @@ ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous, TRA
|
||||
cld->set_next(next);
|
||||
ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next);
|
||||
if (exchanged == next) {
|
||||
if (TraceClassLoaderData) {
|
||||
ResourceMark rm;
|
||||
tty->print("[ClassLoaderData: ");
|
||||
tty->print("create class loader data " INTPTR_FORMAT, p2i(cld));
|
||||
tty->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)cld->class_loader()),
|
||||
cld->loader_name());
|
||||
tty->print_cr("]");
|
||||
if (log_is_enabled(Debug, classloaderdata)) {
|
||||
PauseNoSafepointVerifier pnsv(&no_safepoints); // Need safe points for JavaCalls::call_virtual
|
||||
log_creation(loader, cld, CHECK_NULL);
|
||||
}
|
||||
return cld;
|
||||
}
|
||||
next = exchanged;
|
||||
} while (true);
|
||||
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::log_creation(Handle loader, ClassLoaderData* cld, TRAPS) {
|
||||
Handle string;
|
||||
if (loader.not_null()) {
|
||||
// Include the result of loader.toString() in the output. This allows
|
||||
// the user of the log to identify the class loader instance.
|
||||
JavaValue result(T_OBJECT);
|
||||
KlassHandle spec_klass(THREAD, SystemDictionary::ClassLoader_klass());
|
||||
JavaCalls::call_virtual(&result,
|
||||
loader,
|
||||
spec_klass,
|
||||
vmSymbols::toString_name(),
|
||||
vmSymbols::void_string_signature(),
|
||||
CHECK);
|
||||
assert(result.get_type() == T_OBJECT, "just checking");
|
||||
string = (oop)result.get_jobject();
|
||||
}
|
||||
|
||||
ResourceMark rm;
|
||||
outputStream* log = LogHandle(classloaderdata)::debug_stream();
|
||||
log->print("create class loader data " INTPTR_FORMAT, p2i(cld));
|
||||
log->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)cld->class_loader()),
|
||||
cld->loader_name());
|
||||
|
||||
if (string.not_null()) {
|
||||
log->print(": ");
|
||||
java_lang_String::print(string(), log);
|
||||
}
|
||||
log->cr();
|
||||
}
|
||||
|
||||
|
||||
void ClassLoaderDataGraph::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
|
||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||
cld->oops_do(f, klass_closure, must_claim);
|
||||
@ -709,10 +738,11 @@ GrowableArray<ClassLoaderData*>* ClassLoaderDataGraph::new_clds() {
|
||||
if (!curr->claimed()) {
|
||||
array->push(curr);
|
||||
|
||||
if (TraceClassLoaderData) {
|
||||
tty->print("[ClassLoaderData] found new CLD: ");
|
||||
curr->print_value_on(tty);
|
||||
tty->cr();
|
||||
if (log_is_enabled(Debug, classloaderdata)) {
|
||||
outputStream* log = LogHandle(classloaderdata)::debug_stream();
|
||||
log->print("found new CLD: ");
|
||||
curr->print_value_on(log);
|
||||
log->cr();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,6 +116,7 @@ class ClassLoaderDataGraph : public AllStatic {
|
||||
static void dump_on(outputStream * const out) PRODUCT_RETURN;
|
||||
static void dump() { dump_on(tty); }
|
||||
static void verify();
|
||||
static void log_creation(Handle loader, ClassLoaderData* cld, TRAPS);
|
||||
|
||||
static bool unload_list_contains(const void* x);
|
||||
#ifndef PRODUCT
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2016, 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
|
||||
@ -129,7 +129,7 @@ compute_offset(int &dest_offset,
|
||||
tty->print_cr(" name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int());
|
||||
}
|
||||
#endif //PRODUCT
|
||||
vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class");
|
||||
vm_exit_during_initialization("Invalid layout of preloaded class: use -Xlog:classload=info to see the origin of the problem class");
|
||||
}
|
||||
dest_offset = fd.offset();
|
||||
}
|
||||
@ -3958,7 +3958,7 @@ int InjectedField::compute_offset() {
|
||||
tty->print_cr(" name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int());
|
||||
}
|
||||
#endif //PRODUCT
|
||||
vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class");
|
||||
vm_exit_during_initialization("Invalid layout of preloaded class: use -Xlog:classload=info to see the origin of the problem class");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1302,14 +1302,13 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik,
|
||||
ik->restore_unshareable_info(loader_data, protection_domain, CHECK_(nh));
|
||||
}
|
||||
|
||||
if (TraceClassLoading) {
|
||||
ResourceMark rm;
|
||||
tty->print("[Loaded %s", ik->external_name());
|
||||
tty->print(" from shared objects file");
|
||||
if (class_loader.not_null()) {
|
||||
tty->print(" by %s", loader_data->loader_name());
|
||||
}
|
||||
tty->print_cr("]");
|
||||
if (log_is_enabled(Info, classload)) {
|
||||
ik()->print_loading_log(LogLevel::Info, loader_data, NULL);
|
||||
}
|
||||
// No 'else' here as logging levels are not mutually exclusive
|
||||
|
||||
if (log_is_enabled(Debug, classload)) {
|
||||
ik()->print_loading_log(LogLevel::Debug, loader_data, NULL);
|
||||
}
|
||||
|
||||
if (DumpLoadedClassList != NULL && classlist_file->is_open()) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2016, 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
|
||||
@ -48,6 +48,7 @@
|
||||
#include "utilities/dtrace.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/xmlstream.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#ifdef TARGET_ARCH_x86
|
||||
# include "nativeInst_x86.hpp"
|
||||
#endif
|
||||
@ -1310,13 +1311,14 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) {
|
||||
flush_dependencies(is_alive);
|
||||
|
||||
// Break cycle between nmethod & method
|
||||
if (TraceClassUnloading && WizardMode) {
|
||||
tty->print_cr("[Class unloading: Making nmethod " INTPTR_FORMAT
|
||||
" unloadable], Method*(" INTPTR_FORMAT
|
||||
if (log_is_enabled(Trace, classunload)) {
|
||||
outputStream* log = LogHandle(classunload)::trace_stream();
|
||||
log->print_cr("making nmethod " INTPTR_FORMAT
|
||||
" unloadable, Method*(" INTPTR_FORMAT
|
||||
"), cause(" INTPTR_FORMAT ")",
|
||||
p2i(this), p2i(_method), p2i(cause));
|
||||
if (!Universe::heap()->is_gc_active())
|
||||
cause->klass()->print();
|
||||
cause->klass()->print_on(log);
|
||||
}
|
||||
// Unlink the osr method, so we do not look this up again
|
||||
if (is_osr_method()) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
@ -39,6 +39,9 @@
|
||||
LOG_TAG(classhisto) \
|
||||
LOG_TAG(classresolve) \
|
||||
LOG_TAG(classinit) \
|
||||
LOG_TAG(classload) /* Trace all classes loaded */ \
|
||||
LOG_TAG(classloaderdata) /* class loader loader_data lifetime */ \
|
||||
LOG_TAG(classunload) /* Trace unloading of classes */ \
|
||||
LOG_TAG(comp) \
|
||||
LOG_TAG(compaction) \
|
||||
LOG_TAG(cpu) \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2016, 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
|
||||
@ -208,7 +208,7 @@ void FileMapInfo::allocate_classpath_entry_table() {
|
||||
count ++;
|
||||
bytes += (int)entry_size;
|
||||
bytes += name_bytes;
|
||||
if (TraceClassPaths || (TraceClassLoading && Verbose)) {
|
||||
if (TraceClassPaths) {
|
||||
tty->print_cr("[Add main shared path (%s) %s]", (cpe->is_jar_file() ? "jar" : "dir"), name);
|
||||
}
|
||||
} else {
|
||||
@ -275,7 +275,7 @@ bool FileMapInfo::validate_classpath_entry_table() {
|
||||
struct stat st;
|
||||
const char* name = ent->_name;
|
||||
bool ok = true;
|
||||
if (TraceClassPaths || (TraceClassLoading && Verbose)) {
|
||||
if (TraceClassPaths) {
|
||||
tty->print_cr("[Checking shared classpath entry: %s]", name);
|
||||
}
|
||||
if (os::stat(name, &st) != 0) {
|
||||
@ -301,7 +301,7 @@ bool FileMapInfo::validate_classpath_entry_table() {
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
if (TraceClassPaths || (TraceClassLoading && Verbose)) {
|
||||
if (TraceClassPaths) {
|
||||
tty->print_cr("[ok]");
|
||||
}
|
||||
} else if (!PrintSharedArchiveAndExit) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2015, 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
|
||||
@ -24,6 +24,7 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/classFileParser.hpp"
|
||||
#include "classfile/classFileStream.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/verifier.hpp"
|
||||
@ -35,6 +36,7 @@
|
||||
#include "interpreter/oopMapCache.hpp"
|
||||
#include "interpreter/rewriter.hpp"
|
||||
#include "jvmtifiles/jvmti.h"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "memory/iterator.inline.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
@ -2904,6 +2906,79 @@ const char* InstanceKlass::internal_name() const {
|
||||
return external_name();
|
||||
}
|
||||
|
||||
void InstanceKlass::print_loading_log(LogLevel::type type,
|
||||
ClassLoaderData* loader_data,
|
||||
const ClassFileStream* cfs) const {
|
||||
ResourceMark rm;
|
||||
outputStream* log;
|
||||
|
||||
assert(type == LogLevel::Info || type == LogLevel::Debug, "sanity");
|
||||
|
||||
if (type == LogLevel::Info) {
|
||||
log = LogHandle(classload)::info_stream();
|
||||
} else {
|
||||
assert(type == LogLevel::Debug,
|
||||
"print_loading_log supports only Debug and Info levels");
|
||||
log = LogHandle(classload)::debug_stream();
|
||||
}
|
||||
|
||||
// Name and class hierarchy info
|
||||
log->print("%s", external_name());
|
||||
|
||||
// Source
|
||||
if (cfs != NULL) {
|
||||
if (cfs->source() != NULL) {
|
||||
log->print(" source: %s", cfs->source());
|
||||
} else if (loader_data == ClassLoaderData::the_null_class_loader_data()) {
|
||||
Thread* THREAD = Thread::current();
|
||||
Klass* caller =
|
||||
THREAD->is_Java_thread()
|
||||
? ((JavaThread*)THREAD)->security_get_caller_class(1)
|
||||
: NULL;
|
||||
// caller can be NULL, for example, during a JVMTI VM_Init hook
|
||||
if (caller != NULL) {
|
||||
log->print(" source: instance of %s", caller->external_name());
|
||||
} else {
|
||||
// source is unknown
|
||||
}
|
||||
} else {
|
||||
Handle class_loader(loader_data->class_loader());
|
||||
log->print(" source: %s", class_loader->klass()->external_name());
|
||||
}
|
||||
} else {
|
||||
log->print(" source: shared objects file");
|
||||
}
|
||||
|
||||
if (type == LogLevel::Debug) {
|
||||
// Class hierarchy info
|
||||
log->print(" klass: " INTPTR_FORMAT " super: " INTPTR_FORMAT,
|
||||
p2i(this), p2i(superklass()));
|
||||
|
||||
if (local_interfaces() != NULL && local_interfaces()->length() > 0) {
|
||||
log->print(" interfaces:");
|
||||
int length = local_interfaces()->length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
log->print(" " INTPTR_FORMAT,
|
||||
p2i(InstanceKlass::cast(local_interfaces()->at(i))));
|
||||
}
|
||||
}
|
||||
|
||||
// Class loader
|
||||
log->print(" loader: [");
|
||||
loader_data->print_value_on(log);
|
||||
log->print("]");
|
||||
|
||||
// Classfile checksum
|
||||
if (cfs) {
|
||||
log->print(" bytes: %d checksum: %08x",
|
||||
cfs->length(),
|
||||
ClassLoader::crc32(0, (const char*)cfs->buffer(),
|
||||
cfs->length()));
|
||||
}
|
||||
}
|
||||
log->cr();
|
||||
}
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
// Size Statistics
|
||||
void InstanceKlass::collect_statistics(KlassSizeStats *sz) const {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2015, 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,7 @@
|
||||
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "gc/shared/specialized_oop_closures.hpp"
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "memory/referenceType.hpp"
|
||||
#include "oops/annotations.hpp"
|
||||
#include "oops/constMethod.hpp"
|
||||
@ -1244,6 +1245,9 @@ public:
|
||||
void verify_on(outputStream* st);
|
||||
|
||||
void oop_verify_on(oop obj, outputStream* st);
|
||||
|
||||
// Logging
|
||||
void print_loading_log(LogLevel::type type, ClassLoaderData* loader_data, const ClassFileStream* cfs) const;
|
||||
};
|
||||
|
||||
// for adding methods
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2015, 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
|
||||
@ -28,6 +28,7 @@
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "gc/shared/collectedHeap.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
@ -386,9 +387,9 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive, bool clean_alive
|
||||
Klass* sub = current->subklass();
|
||||
while (sub != NULL && !sub->is_loader_alive(is_alive)) {
|
||||
#ifndef PRODUCT
|
||||
if (TraceClassUnloading && WizardMode) {
|
||||
if (log_is_enabled(Trace, classunload)) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("[Unlinking class (subclass) %s]", sub->external_name());
|
||||
log_trace(classunload)("unlinking class (subclass): %s", sub->external_name());
|
||||
}
|
||||
#endif
|
||||
sub = sub->next_sibling();
|
||||
@ -401,9 +402,9 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive, bool clean_alive
|
||||
// Find and set the first alive sibling
|
||||
Klass* sibling = current->next_sibling();
|
||||
while (sibling != NULL && !sibling->is_loader_alive(is_alive)) {
|
||||
if (TraceClassUnloading && WizardMode) {
|
||||
if (log_is_enabled(Trace, classunload)) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("[Unlinking class (sibling) %s]", sibling->external_name());
|
||||
log_trace(classunload)("[Unlinking class (sibling) %s]", sibling->external_name());
|
||||
}
|
||||
sibling = sibling->next_sibling();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2016, 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
|
||||
@ -29,6 +29,7 @@
|
||||
#include "interpreter/bytecodeStream.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "jvmtifiles/jvmtiEnv.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "memory/universe.inline.hpp"
|
||||
@ -473,9 +474,7 @@ JvmtiEnv::AddToBootstrapClassLoaderSearch(const char* segment) {
|
||||
ObjectLocker ol(loader_lock, thread);
|
||||
|
||||
// add the jar file to the bootclasspath
|
||||
if (TraceClassLoading) {
|
||||
tty->print_cr("[Opened %s]", zip_entry->name());
|
||||
}
|
||||
log_info(classload)("opened: %s", zip_entry->name());
|
||||
ClassLoaderExt::append_boot_classpath(zip_entry);
|
||||
return JVMTI_ERROR_NONE;
|
||||
} else {
|
||||
@ -625,8 +624,13 @@ JvmtiEnv::SetVerboseFlag(jvmtiVerboseFlag flag, jboolean value) {
|
||||
// ignore
|
||||
break;
|
||||
case JVMTI_VERBOSE_CLASS:
|
||||
TraceClassLoading = value != 0;
|
||||
TraceClassUnloading = value != 0;
|
||||
if (value == 0) {
|
||||
LogConfiguration::parse_log_arguments("stdout", "classunload=off", NULL, NULL, NULL);
|
||||
LogConfiguration::parse_log_arguments("stdout", "classload=off", NULL, NULL, NULL);
|
||||
} else {
|
||||
LogConfiguration::parse_log_arguments("stdout", "classload=info", NULL, NULL, NULL);
|
||||
LogConfiguration::parse_log_arguments("stdout", "classunload=info", NULL, NULL, NULL);
|
||||
}
|
||||
break;
|
||||
case JVMTI_VERBOSE_GC:
|
||||
if (value == 0) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016, 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
|
||||
@ -1407,7 +1407,7 @@ int WhiteBox::offset_for_field(const char* field_name, oop object,
|
||||
if (res == NULL) {
|
||||
tty->print_cr("Invalid layout of %s at %s", ik->external_name(),
|
||||
name_symbol->as_C_string());
|
||||
vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class");
|
||||
vm_exit_during_initialization("Invalid layout of preloaded class: use -Xlog:classload=info to see the origin of the problem class");
|
||||
}
|
||||
|
||||
//fetch the field at the offset we've found
|
||||
|
@ -402,10 +402,12 @@ static AliasedFlag const aliased_jvm_flags[] = {
|
||||
};
|
||||
|
||||
static AliasedLoggingFlag const aliased_logging_flags[] = {
|
||||
{ "TraceClassResolution", LogLevel::Info, true, LogTag::_classresolve },
|
||||
{ "TraceExceptions", LogLevel::Info, true, LogTag::_exceptions },
|
||||
{ "TraceMonitorInflation", LogLevel::Debug, true, LogTag::_monitorinflation },
|
||||
{ NULL, LogLevel::Off, false, LogTag::__NO_TAG }
|
||||
{ "TraceClassLoading", LogLevel::Info, true, LogTag::_classload },
|
||||
{ "TraceClassUnloading", LogLevel::Info, true, LogTag::_classunload },
|
||||
{ "TraceClassResolution", LogLevel::Info, true, LogTag::_classresolve },
|
||||
{ "TraceExceptions", LogLevel::Info, true, LogTag::_exceptions },
|
||||
{ "TraceMonitorInflation", LogLevel::Debug, true, LogTag::_monitorinflation },
|
||||
{ NULL, LogLevel::Off, false, LogTag::__NO_TAG }
|
||||
};
|
||||
|
||||
// Return true if "v" is less than "other", where "other" may be "undefined".
|
||||
@ -2653,12 +2655,8 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args,
|
||||
// -verbose:[class/gc/jni]
|
||||
if (match_option(option, "-verbose", &tail)) {
|
||||
if (!strcmp(tail, ":class") || !strcmp(tail, "")) {
|
||||
if (FLAG_SET_CMDLINE(bool, TraceClassLoading, true) != Flag::SUCCESS) {
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
if (FLAG_SET_CMDLINE(bool, TraceClassUnloading, true) != Flag::SUCCESS) {
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(classload));
|
||||
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(classunload));
|
||||
} else if (!strcmp(tail, ":gc")) {
|
||||
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(gc));
|
||||
} else if (!strcmp(tail, ":jni")) {
|
||||
|
@ -2416,21 +2416,12 @@ public:
|
||||
product(bool, TraceClassPaths, false, \
|
||||
"Trace processing of class paths") \
|
||||
\
|
||||
product_rw(bool, TraceClassLoading, false, \
|
||||
"Trace all classes loaded") \
|
||||
\
|
||||
product(bool, TraceClassLoadingPreorder, false, \
|
||||
"Trace all classes loaded in order referenced (not loaded)") \
|
||||
\
|
||||
product_rw(bool, TraceClassUnloading, false, \
|
||||
"Trace unloading of classes") \
|
||||
\
|
||||
product_rw(bool, TraceLoaderConstraints, false, \
|
||||
"Trace loader constraints") \
|
||||
\
|
||||
develop(bool, TraceClassLoaderData, false, \
|
||||
"Trace class loader loader_data lifetime") \
|
||||
\
|
||||
product(size_t, InitialBootClassLoaderMetaspaceSize, \
|
||||
NOT_LP64(2200*K) LP64_ONLY(4*M), \
|
||||
"Initial size of the boot class loader data metaspace") \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2016, 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
|
||||
@ -33,6 +33,8 @@
|
||||
#include "utilities/dtrace.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/defaultStream.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
|
||||
#ifdef DTRACE_ENABLED
|
||||
|
||||
@ -135,9 +137,9 @@ void ClassLoadingService::notify_class_unloaded(InstanceKlass* k) {
|
||||
}
|
||||
}
|
||||
|
||||
if (TraceClassUnloading) {
|
||||
if (log_is_enabled(Info, classunload)) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("[Unloading class %s " INTPTR_FORMAT "]", k->external_name(), p2i(k));
|
||||
log_info(classunload)("unloading class %s " INTPTR_FORMAT , k->external_name(), p2i(k));
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,12 +181,13 @@ size_t ClassLoadingService::compute_class_size(InstanceKlass* k) {
|
||||
|
||||
bool ClassLoadingService::set_verbose(bool verbose) {
|
||||
MutexLocker m(Management_lock);
|
||||
|
||||
// verbose will be set to the previous value
|
||||
Flag::Error error = CommandLineFlags::boolAtPut("TraceClassLoading", &verbose, Flag::MANAGEMENT);
|
||||
assert(error==Flag::SUCCESS, "Setting TraceClassLoading flag failed with error %s", Flag::flag_error_str(error));
|
||||
if (verbose) {
|
||||
LogConfiguration::parse_log_arguments("stdout", "classload=info", NULL, NULL, NULL);
|
||||
} else {
|
||||
LogConfiguration::parse_log_arguments("stdout", "classload=off", NULL, NULL, NULL);
|
||||
}
|
||||
reset_trace_class_unloading();
|
||||
|
||||
return verbose;
|
||||
}
|
||||
|
||||
@ -192,8 +195,11 @@ bool ClassLoadingService::set_verbose(bool verbose) {
|
||||
void ClassLoadingService::reset_trace_class_unloading() {
|
||||
assert(Management_lock->owned_by_self(), "Must own the Management_lock");
|
||||
bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose();
|
||||
Flag::Error error = CommandLineFlags::boolAtPut("TraceClassUnloading", &value, Flag::MANAGEMENT);
|
||||
assert(error==Flag::SUCCESS, "Setting TraceClassUnLoading flag failed with error %s", Flag::flag_error_str(error));
|
||||
if (value) {
|
||||
LogConfiguration::parse_log_arguments("stdout", "classunload=info", NULL, NULL, NULL);
|
||||
} else {
|
||||
LogConfiguration::parse_log_arguments("stdout", "classunload=off", NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
GrowableArray<KlassHandle>* LoadedClassesEnumerator::_loaded_classes = NULL;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2016, 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
|
||||
@ -25,6 +25,7 @@
|
||||
#ifndef SHARE_VM_SERVICES_CLASSLOADINGSERVICE_HPP
|
||||
#define SHARE_VM_SERVICES_CLASSLOADINGSERVICE_HPP
|
||||
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
#include "runtime/perfData.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
@ -54,7 +55,7 @@ private:
|
||||
public:
|
||||
static void init();
|
||||
|
||||
static bool get_verbose() { return TraceClassLoading; }
|
||||
static bool get_verbose() { return log_is_enabled(Info, classload); }
|
||||
static bool set_verbose(bool verbose);
|
||||
static void reset_trace_class_unloading() NOT_MANAGEMENT_RETURN;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2016, 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
|
||||
@ -24,7 +24,7 @@
|
||||
/**
|
||||
* @test
|
||||
* @bug 8057967
|
||||
* @run main/bootclasspath -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+TraceClassUnloading
|
||||
* @run main/bootclasspath -Xbatch -XX:+IgnoreUnrecognizedVMOptions -Xlog:classunload
|
||||
* -XX:+PrintCompilation -XX:+TraceDependencies -XX:+TraceReferenceGC
|
||||
* -verbose:gc java.lang.invoke.CallSiteDepContextTest
|
||||
*/
|
||||
|
128
hotspot/test/runtime/logging/ClassLoadUnloadTest.java
Normal file
128
hotspot/test/runtime/logging/ClassLoadUnloadTest.java
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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 ClassLoadUnloadTest
|
||||
* @bug 8142506
|
||||
* @library /testlibrary /runtime/testlibrary
|
||||
* @library classes
|
||||
* @build ClassUnloadCommon test.Empty jdk.test.lib.* jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools
|
||||
* @run driver ClassLoadUnloadTest
|
||||
*/
|
||||
|
||||
import jdk.test.lib.*;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ClassLoadUnloadTest {
|
||||
private static OutputAnalyzer out;
|
||||
private static ProcessBuilder pb;
|
||||
private static class ClassUnloadTestMain {
|
||||
public static void main(String... args) throws Exception {
|
||||
String className = "test.Empty";
|
||||
ClassLoader cl = ClassUnloadCommon.newClassLoader();
|
||||
Class<?> c = cl.loadClass(className);
|
||||
cl = null; c = null;
|
||||
ClassUnloadCommon.triggerUnloading();
|
||||
}
|
||||
}
|
||||
|
||||
static void checkFor(String... outputStrings) throws Exception {
|
||||
out = new OutputAnalyzer(pb.start());
|
||||
for (String s: outputStrings) {
|
||||
out.shouldContain(s);
|
||||
}
|
||||
out.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
static void checkAbsent(String... outputStrings) throws Exception {
|
||||
out = new OutputAnalyzer(pb.start());
|
||||
for (String s: outputStrings) {
|
||||
out.shouldNotContain(s);
|
||||
}
|
||||
out.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
// Use the same command-line heap size setting as ../ClassUnload/UnloadTest.java
|
||||
static ProcessBuilder exec(String... args) throws Exception {
|
||||
List<String> argsList = new ArrayList<>();
|
||||
Collections.addAll(argsList, args);
|
||||
Collections.addAll(argsList, "-Xmn8m");
|
||||
Collections.addAll(argsList, "-Dtest.classes=" + System.getProperty("test.classes","."));
|
||||
Collections.addAll(argsList, ClassUnloadTestMain.class.getName());
|
||||
return ProcessTools.createJavaProcessBuilder(argsList.toArray(new String[argsList.size()]));
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
|
||||
// -Xlog:classunload=info
|
||||
pb = exec("-Xlog:classunload=info");
|
||||
checkFor("[classunload]", "unloading class");
|
||||
|
||||
// -Xlog:classunload=off
|
||||
pb = exec("-Xlog:classunload=off");
|
||||
checkAbsent("[classunload]");
|
||||
|
||||
// -XX:+TraceClassUnloading
|
||||
pb = exec("-XX:+TraceClassUnloading");
|
||||
checkFor("[classunload]", "unloading class");
|
||||
|
||||
// -XX:-TraceClassUnloading
|
||||
pb = exec("-XX:-TraceClassUnloading");
|
||||
checkAbsent("[classunload]");
|
||||
|
||||
// -Xlog:classload=info
|
||||
pb = exec("-Xlog:classload=info");
|
||||
checkFor("[classload]", "java.lang.Object", "source:");
|
||||
|
||||
// -Xlog:classload=debug
|
||||
pb = exec("-Xlog:classload=debug");
|
||||
checkFor("[classload]", "java.lang.Object", "source:", "klass:", "super:", "loader:", "bytes:");
|
||||
|
||||
// -Xlog:classload=off
|
||||
pb = exec("-Xlog:classload=off");
|
||||
checkAbsent("[classload]");
|
||||
|
||||
// -XX:+TraceClassLoading
|
||||
pb = exec("-XX:+TraceClassLoading");
|
||||
checkFor("[classload]", "java.lang.Object", "source:");
|
||||
|
||||
// -XX:-TraceClassLoading
|
||||
pb = exec("-XX:-TraceClassLoading");
|
||||
checkAbsent("[classload]");
|
||||
|
||||
// -verbose:class
|
||||
pb = exec("-verbose:class");
|
||||
checkFor("[classload]", "java.lang.Object", "source:");
|
||||
checkFor("[classunload]", "unloading class");
|
||||
|
||||
// -Xlog:classloaderdata=trace
|
||||
pb = exec("-Xlog:classloaderdata=trace");
|
||||
checkFor("[classloaderdata]", "create class loader data");
|
||||
|
||||
}
|
||||
}
|
5
hotspot/test/runtime/logging/classes/test/Empty.java
Normal file
5
hotspot/test/runtime/logging/classes/test/Empty.java
Normal file
@ -0,0 +1,5 @@
|
||||
package test;
|
||||
|
||||
public class Empty {
|
||||
public String toString() { return "nothing"; }
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2016, 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
|
||||
@ -21,6 +21,12 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* To use ClassUnloadCommon from a sub-process, see hotspot/test/runtime/logging/ClassLoadUnloadTest.java
|
||||
* for an example.
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
Loading…
x
Reference in New Issue
Block a user