< prev index next >
src/hotspot/share/classfile/classLoaderData.cpp
Print this page
@@ -52,10 +52,11 @@
#include "classfile/dictionary.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/packageEntry.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/metadataFactory.hpp"
@@ -99,25 +100,47 @@
_the_null_class_loader_data->print_value_on(&ls);
ls.cr();
}
}
+// JFR and logging support so that the name and klass are available after the
+// class_loader oop is no longer alive, during unloading.
+void ClassLoaderData::initialize_name_and_klass(Handle class_loader) {
+ _class_loader_klass = class_loader->klass();
+ oop class_loader_name = java_lang_ClassLoader::name(class_loader());
+ if (class_loader_name != NULL) {
+ Thread* THREAD = Thread::current();
+ ResourceMark rm(THREAD);
+ const char* class_loader_instance_name =
+ java_lang_String::as_utf8_string(class_loader_name);
+
+ if (class_loader_instance_name != NULL && class_loader_instance_name[0] != '\0') {
+ // Can't throw InternalError and SymbolTable doesn't throw OOM anymore.
+ _class_loader_name = SymbolTable::new_symbol(class_loader_instance_name, CATCH);
+ }
+ }
+}
+
ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
- _class_loader(h_class_loader()),
_is_anonymous(is_anonymous),
// An anonymous class loader data doesn't have anything to keep
// it from being unloaded during parsing of the anonymous class.
// The null-class-loader should always be kept alive.
_keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0),
_metaspace(NULL), _unloading(false), _klasses(NULL),
_modules(NULL), _packages(NULL), _unnamed_module(NULL), _dictionary(NULL),
_claimed(0), _modified_oops(true), _accumulated_modified_oops(false),
_jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
_next(NULL),
+ _class_loader_klass(NULL), _class_loader_name(NULL),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
Monitor::_safepoint_check_never)) {
+ if (!h_class_loader.is_null()) {
+ _class_loader = _handles.add(h_class_loader());
+ }
+
if (!is_anonymous) {
// The holder is initialized later for anonymous classes, and before calling anything
// that call class_loader().
initialize_holder(h_class_loader);
@@ -266,11 +289,10 @@
// Only clear modified_oops after the ClassLoaderData is claimed.
if (clear_mod_oops) {
clear_modified_oops();
}
- f->do_oop(&_class_loader);
_handles.oops_do(f);
}
void ClassLoaderData::classes_do(KlassClosure* klass_closure) {
// Lock-free access requires load_acquire
@@ -553,11 +575,11 @@
LogTarget(Debug, class, loader, data) lt;
if (lt.is_enabled()) {
ResourceMark rm;
LogStream ls(lt);
- ls.print("unload ");
+ ls.print("unload");
print_value_on(&ls);
ls.cr();
}
// Some items on the _deallocate_list need to free their C heap structures
@@ -628,11 +650,11 @@
}
// Unloading support
bool ClassLoaderData::is_alive() const {
bool alive = keep_alive() // null class loader and incomplete anonymous klasses.
- || (_holder.peek() != NULL); // not cleaned by weak reference processing
+ || (_holder.peek() != NULL); // and not cleaned by the GC weak handle processing.
return alive;
}
class ReleaseKlassClosure: public KlassClosure {
@@ -884,17 +906,27 @@
// Add a new class loader data to the graph.
return ClassLoaderDataGraph::add(loader, true);
}
const char* ClassLoaderData::loader_name() const {
+ if (is_unloading()) {
+ if (_class_loader_klass == NULL) {
+ return "<bootloader>";
+ } else if (_class_loader_name != NULL) {
+ return _class_loader_name->as_C_string();
+ } else {
+ return _class_loader_klass->name()->as_C_string();
+ }
+ } else {
// Handles null class loader
return SystemDictionary::loader_name(class_loader());
+ }
}
void ClassLoaderData::print_value_on(outputStream* out) const {
- if (class_loader() != NULL) {
+ if (!is_unloading() && class_loader() != NULL) {
out->print("loader data: " INTPTR_FORMAT " for instance ", p2i(this));
class_loader()->print_value_on(out); // includes loader_name() and address of class loader instance
} else {
// loader data: 0xsomeaddr of <bootloader>
out->print("loader data: " INTPTR_FORMAT " of %s", p2i(this), loader_name());
@@ -905,11 +937,11 @@
}
#ifndef PRODUCT
void ClassLoaderData::print_on(outputStream* out) const {
out->print("ClassLoaderData CLD: " PTR_FORMAT ", loader: " PTR_FORMAT ", loader_klass: %s {",
- p2i(this), p2i((void *)class_loader()), loader_name());
+ p2i(this), p2i((void *)_class_loader.ptr_raw()), loader_name());
if (is_anonymous()) out->print(" anonymous");
if (claimed()) out->print(" claimed");
if (is_unloading()) out->print(" unloading");
out->print(" metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null()));
@@ -959,14 +991,14 @@
bool ClassLoaderDataGraph::_should_purge = false;
bool ClassLoaderDataGraph::_metaspace_oom = false;
// Add a new class loader data node to the list. Assign the newly created
// ClassLoaderData into the java/lang/ClassLoader object as a hidden field
-ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous) {
+ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool is_anonymous) {
NoSafepointVerifier no_safepoints; // we mustn't GC until we've installed the
// ClassLoaderData in the graph since the CLD
- // contains unhandled oops
+ // contains oops in _handles that must be walked.
ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous);
if (!is_anonymous) {
// First, Atomically set it
@@ -999,10 +1031,20 @@
}
next = exchanged;
} while (true);
}
+ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous) {
+ ClassLoaderData* loader_data = add_to_graph(loader, is_anonymous);
+ // Initialize name and class after the loader data is added to the CLDG
+ // because adding the Symbol for the name might safepoint.
+ if (loader.not_null()) {
+ loader_data->initialize_name_and_klass(loader);
+ }
+ return loader_data;
+}
+
void ClassLoaderDataGraph::oops_do(OopClosure* f, bool must_claim) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
cld->oops_do(f, must_claim);
}
}
< prev index next >