// 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; }
// 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; }
// 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); }