void ClassLoaderDataGraph::keep_alive_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { if (cld->keep_alive()) { cld->oops_do(f, klass_closure, must_claim); } } }
void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); // Only walk the head until any clds not purged from prior unloading // (CMS doesn't purge right away). for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { cld->classes_do(f); } }
void ClassLoaderDataGraph::roots_cld_do(CLDClosure* strong, CLDClosure* weak) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) { CLDClosure* closure = cld->keep_alive() ? strong : weak; if (closure != NULL) { closure->do_cld(cld); } } }
bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) { for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { if (loader_data == data) { return true; } } return false; }
bool ClassLoaderDataGraph::unload_list_contains(const void* x) { assert(SafepointSynchronize::is_at_safepoint(), "only safe to call at safepoint"); for (ClassLoaderData* cld = _unloading; cld != NULL; cld = cld->next()) { if (cld->metaspace_or_null() != NULL && cld->metaspace_or_null()->contains(x)) { return true; } } return false; }
ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic() : _next_klass(NULL) { ClassLoaderData* cld = ClassLoaderDataGraph::_head; Klass* klass = NULL; // Find the first klass in the CLDG. while (cld != NULL) { klass = cld->_klasses; if (klass != NULL) { _next_klass = klass; return; } cld = cld->next(); } }
// 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, TRAPS) { // We need to allocate all the oops for the ClassLoaderData before allocating the // actual ClassLoaderData object. ClassLoaderData::Dependencies dependencies(CHECK_NULL); No_Safepoint_Verifier no_safepoints; // we mustn't GC until we've installed the // ClassLoaderData in the graph since the CLD // contains unhandled oops ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous, dependencies); if (!is_anonymous) { ClassLoaderData** cld_addr = java_lang_ClassLoader::loader_data_addr(loader()); // First, Atomically set it ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL); if (old != NULL) { delete cld; // Returns the data. return old; } } // We won the race, and therefore the task of adding the data to the list of // class loader data ClassLoaderData** list_head = &_head; ClassLoaderData* next = _head; do { 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("]"); } return cld; } next = exchanged; } while (true); }
Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass_in_cldg(Klass* klass) { Klass* next = klass->next_link(); if (next != NULL) { return next; } // No more klasses in the current CLD. Time to find a new CLD. ClassLoaderData* cld = klass->class_loader_data(); while (next == NULL) { cld = cld->next(); if (cld == NULL) { break; } next = cld->_klasses; } return next; }
GrowableArray<ClassLoaderData*>* ClassLoaderDataGraph::new_clds() { assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?"); GrowableArray<ClassLoaderData*>* array = new GrowableArray<ClassLoaderData*>(); // The CLDs in [_head, _saved_head] were all added during last call to remember_new_clds(true); ClassLoaderData* curr = _head; while (curr != _saved_head) { if (!curr->claimed()) { array->push(curr); if (TraceClassLoaderData) { tty->print("[ClassLoaderData] found new CLD: "); curr->print_value_on(tty); tty->cr(); } } curr = curr->_next; } return array; }
// Move class loader data from main list to the unloaded list for unloading // and deallocation later. bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) { ClassLoaderData* data = _head; ClassLoaderData* prev = NULL; bool seen_dead_loader = false; // Save previous _unloading pointer for CMS which may add to unloading list before // purging and we don't want to rewalk the previously unloaded class loader data. _saved_unloading = _unloading; // mark metadata seen on the stack and code cache so we can delete // unneeded entries. bool has_redefined_a_class = JvmtiExport::has_redefined_a_class(); MetadataOnStackMark md_on_stack; while (data != NULL) { if (data->is_alive(is_alive_closure)) { if (has_redefined_a_class) { data->classes_do(InstanceKlass::purge_previous_versions); } data->free_deallocate_list(); prev = data; data = data->next(); continue; } seen_dead_loader = true; ClassLoaderData* dead = data; dead->unload(); data = data->next(); // Remove from loader list. // This class loader data will no longer be found // in the ClassLoaderDataGraph. if (prev != NULL) { prev->set_next(data); } else { assert(dead == _head, "sanity check"); _head = data; } dead->set_next(_unloading); _unloading = dead; } if (seen_dead_loader) { post_class_unload_events(); } return seen_dead_loader; }
// for debugging and hsfind(x) bool ClassLoaderDataGraph::contains(address x) { // I think we need the _metaspace_lock taken here because the class loader // data graph could be changing while we are walking it (new entries added, // new entries being unloaded, etc). if (DumpSharedSpaces) { // There are only two metaspaces to worry about. ClassLoaderData* ncld = ClassLoaderData::the_null_class_loader_data(); return (ncld->ro_metaspace()->contains(x) || ncld->rw_metaspace()->contains(x)); } if (UseSharedSpaces && MetaspaceShared::is_in_shared_space(x)) { return true; } for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { if (cld->metaspace_or_null() != NULL && cld->metaspace_or_null()->contains(x)) { return true; } } // Could also be on an unloading list which is okay, ie. still allocated // for a little while. for (ClassLoaderData* ucld = _unloading; ucld != NULL; ucld = ucld->next()) { if (ucld->metaspace_or_null() != NULL && ucld->metaspace_or_null()->contains(x)) { return true; } } return false; }
void ClassLoaderDataGraph::verify() { for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { data->verify(); } }
void ClassLoaderDataGraph::cld_do(CLDClosure* cl) { for (ClassLoaderData* cld = _head; cl != NULL && cld != NULL; cld = cld->next()) { cl->do_cld(cld); } }
void ClassLoaderDataGraph::clear_claimed_marks() { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { cld->clear_claimed(); } }
// Move class loader data from main list to the unloaded list for unloading // and deallocation later. bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, bool clean_previous_versions) { ClassLoaderData* data = _head; ClassLoaderData* prev = NULL; bool seen_dead_loader = false; // Mark metadata seen on the stack only so we can delete unneeded entries. // Only walk all metadata, including the expensive code cache walk, for Full GC // and only if class redefinition and if there's previous versions of // Klasses to delete. bool walk_all_metadata = clean_previous_versions && JvmtiExport::has_redefined_a_class() && InstanceKlass::has_previous_versions(); MetadataOnStackMark md_on_stack(walk_all_metadata); // Save previous _unloading pointer for CMS which may add to unloading list before // purging and we don't want to rewalk the previously unloaded class loader data. _saved_unloading = _unloading; data = _head; while (data != NULL) { if (data->is_alive(is_alive_closure)) { // clean metaspace if (walk_all_metadata) { data->classes_do(InstanceKlass::purge_previous_versions); } data->free_deallocate_list(); prev = data; data = data->next(); continue; } seen_dead_loader = true; ClassLoaderData* dead = data; dead->unload(); data = data->next(); // Remove from loader list. // This class loader data will no longer be found // in the ClassLoaderDataGraph. if (prev != NULL) { prev->set_next(data); } else { assert(dead == _head, "sanity check"); _head = data; } dead->set_next(_unloading); _unloading = dead; } if (seen_dead_loader) { post_class_unload_events(); } return seen_dead_loader; }
void ClassLoaderDataGraph::methods_do(void f(Method*)) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { cld->methods_do(f); } }
void ClassLoaderDataGraph::classes_do(void f(Klass* const)) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { cld->classes_do(f); } }
void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { cld->loaded_classes_do(klass_closure); } }
void ClassLoaderDataGraph::dump_on(outputStream * const out) { for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { data->dump(out); } MetaspaceAux::dump(out); }
void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); for (ClassLoaderData* cld = _unloading; cld != NULL; cld = cld->next()) { cld->classes_do(f); } }