8306929: Avoid CleanClassLoaderDataMetaspaces safepoints when previous versions are shared

Reviewed-by: coleenp, sspitsyn
This commit is contained in:
Stefan Johansson 2023-05-04 11:00:44 +00:00
parent cecf817f5e
commit 408cec516b
6 changed files with 147 additions and 23 deletions

View file

@ -4022,18 +4022,18 @@ void InstanceKlass::set_init_state(ClassState state) {
// Globally, there is at least one previous version of a class to walk
// during class unloading, which is saved because old methods in the class
// are still running. Otherwise the previous version list is cleaned up.
bool InstanceKlass::_has_previous_versions = false;
bool InstanceKlass::_should_clean_previous_versions = false;
// Returns true if there are previous versions of a class for class
// unloading only. Also resets the flag to false. purge_previous_version
// will set the flag to true if there are any left, i.e., if there's any
// work to do for next time. This is to avoid the expensive code cache
// walk in CLDG::clean_deallocate_lists().
bool InstanceKlass::has_previous_versions_and_reset() {
bool ret = _has_previous_versions;
log_trace(redefine, class, iklass, purge)("Class unloading: has_previous_versions = %s",
bool InstanceKlass::should_clean_previous_versions_and_reset() {
bool ret = _should_clean_previous_versions;
log_trace(redefine, class, iklass, purge)("Class unloading: should_clean_previous_versions = %s",
ret ? "true" : "false");
_has_previous_versions = false;
_should_clean_previous_versions = false;
return ret;
}
@ -4090,12 +4090,17 @@ void InstanceKlass::purge_previous_version_list() {
version++;
continue;
} else {
log_trace(redefine, class, iklass, purge)("previous version " PTR_FORMAT " is alive", p2i(pv_node));
assert(pvcp->pool_holder() != nullptr, "Constant pool with no holder");
guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack");
live_count++;
// found a previous version for next time we do class unloading
_has_previous_versions = true;
if (pvcp->is_shared()) {
// Shared previous versions can never be removed so no cleaning is needed.
log_trace(redefine, class, iklass, purge)("previous version " PTR_FORMAT " is shared", p2i(pv_node));
} else {
// Previous version alive, set that clean is needed for next time.
_should_clean_previous_versions = true;
log_trace(redefine, class, iklass, purge)("previous version " PTR_FORMAT " is alive", p2i(pv_node));
}
}
// next previous version
@ -4195,13 +4200,19 @@ void InstanceKlass::add_previous_version(InstanceKlass* scratch_class,
return;
}
// Add previous version if any methods are still running.
// Set has_previous_version flag for processing during class unloading.
_has_previous_versions = true;
log_trace(redefine, class, iklass, add) ("scratch class added; one of its methods is on_stack.");
// Add previous version if any methods are still running or if this is
// a shared class which should never be removed.
assert(scratch_class->previous_versions() == nullptr, "shouldn't have a previous version");
scratch_class->link_previous_versions(previous_versions());
link_previous_versions(scratch_class);
if (cp_ref->is_shared()) {
log_trace(redefine, class, iklass, add) ("scratch class added; class is shared");
} else {
// We only set clean_previous_versions flag for processing during class
// unloading for non-shared classes.
_should_clean_previous_versions = true;
log_trace(redefine, class, iklass, add) ("scratch class added; one of its methods is on_stack.");
}
} // end add_previous_version()
#endif // INCLUDE_JVMTI