mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8010196: NPG: Internal Error: Metaspace allocation lock -- possible deadlock
Refactor the CLD dependency list into a separate class. Use an ObjectLocker to synchronize additions to the CLD dependency list. Reviewed-by: stefank, coleenp
This commit is contained in:
parent
6f3fdce7b3
commit
0edccc9e61
3 changed files with 159 additions and 17 deletions
|
@ -70,15 +70,19 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
|
|||
_is_anonymous(is_anonymous), _keep_alive(is_anonymous), // initially
|
||||
_metaspace(NULL), _unloading(false), _klasses(NULL),
|
||||
_claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
|
||||
_next(NULL), _dependencies(NULL),
|
||||
_next(NULL), _dependencies(),
|
||||
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) {
|
||||
// empty
|
||||
}
|
||||
|
||||
void ClassLoaderData::init_dependencies(TRAPS) {
|
||||
_dependencies.init(CHECK);
|
||||
}
|
||||
|
||||
void ClassLoaderData::Dependencies::init(TRAPS) {
|
||||
// Create empty dependencies array to add to. CMS requires this to be
|
||||
// an oop so that it can track additions via card marks. We think.
|
||||
_dependencies = (oop)oopFactory::new_objectArray(2, CHECK);
|
||||
_list_head = oopFactory::new_objectArray(2, CHECK);
|
||||
}
|
||||
|
||||
bool ClassLoaderData::claim() {
|
||||
|
@ -95,13 +99,17 @@ void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool m
|
|||
}
|
||||
|
||||
f->do_oop(&_class_loader);
|
||||
f->do_oop(&_dependencies);
|
||||
_dependencies.oops_do(f);
|
||||
_handles->oops_do(f);
|
||||
if (klass_closure != NULL) {
|
||||
classes_do(klass_closure);
|
||||
}
|
||||
}
|
||||
|
||||
void ClassLoaderData::Dependencies::oops_do(OopClosure* f) {
|
||||
f->do_oop((oop*)&_list_head);
|
||||
}
|
||||
|
||||
void ClassLoaderData::classes_do(KlassClosure* klass_closure) {
|
||||
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
|
||||
klass_closure->do_klass(k);
|
||||
|
@ -154,14 +162,14 @@ void ClassLoaderData::record_dependency(Klass* k, TRAPS) {
|
|||
// It's a dependency we won't find through GC, add it. This is relatively rare
|
||||
// Must handle over GC point.
|
||||
Handle dependency(THREAD, to);
|
||||
from_cld->add_dependency(dependency, CHECK);
|
||||
from_cld->_dependencies.add(dependency, CHECK);
|
||||
}
|
||||
|
||||
|
||||
void ClassLoaderData::add_dependency(Handle dependency, TRAPS) {
|
||||
void ClassLoaderData::Dependencies::add(Handle dependency, TRAPS) {
|
||||
// Check first if this dependency is already in the list.
|
||||
// Save a pointer to the last to add to under the lock.
|
||||
objArrayOop ok = (objArrayOop)_dependencies;
|
||||
objArrayOop ok = _list_head;
|
||||
objArrayOop last = NULL;
|
||||
while (ok != NULL) {
|
||||
last = ok;
|
||||
|
@ -184,16 +192,17 @@ void ClassLoaderData::add_dependency(Handle dependency, TRAPS) {
|
|||
objArrayHandle new_dependency(THREAD, deps);
|
||||
|
||||
// Add the dependency under lock
|
||||
locked_add_dependency(last_handle, new_dependency);
|
||||
locked_add(last_handle, new_dependency, THREAD);
|
||||
}
|
||||
|
||||
void ClassLoaderData::locked_add_dependency(objArrayHandle last_handle,
|
||||
objArrayHandle new_dependency) {
|
||||
void ClassLoaderData::Dependencies::locked_add(objArrayHandle last_handle,
|
||||
objArrayHandle new_dependency,
|
||||
Thread* THREAD) {
|
||||
|
||||
// Have to lock and put the new dependency on the end of the dependency
|
||||
// array so the card mark for CMS sees that this dependency is new.
|
||||
// Can probably do this lock free with some effort.
|
||||
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
|
||||
ObjectLocker ol(Handle(THREAD, _list_head), THREAD);
|
||||
|
||||
oop loader_or_mirror = new_dependency->obj_at(0);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue