提交 a7dee824 编写于 作者: S shshahma

8168914: Crash in ClassLoaderData/JNIHandleBlock::oops_do during concurrent marking

Reviewed-by: dholmes, ehelin
上级 7122fc6e
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -78,7 +78,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen
// The null-class-loader should always be kept alive.
_keep_alive(is_anonymous || h_class_loader.is_null()),
_metaspace(NULL), _unloading(false), _klasses(NULL),
_claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
_claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
_next(NULL), _dependencies(dependencies),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) {
// empty
......@@ -96,6 +96,45 @@ void ClassLoaderData::Dependencies::init(TRAPS) {
_list_head = oopFactory::new_objectArray(2, CHECK);
}
ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() {
Chunk* c = _head;
while (c != NULL) {
Chunk* next = c->_next;
delete c;
c = next;
}
}
oop* ClassLoaderData::ChunkedHandleList::add(oop o) {
if (_head == NULL || _head->_size == Chunk::CAPACITY) {
Chunk* next = new Chunk(_head);
OrderAccess::release_store_ptr(&_head, next);
}
oop* handle = &_head->_data[_head->_size];
*handle = o;
OrderAccess::release_store(&_head->_size, _head->_size + 1);
return handle;
}
inline void ClassLoaderData::ChunkedHandleList::oops_do_chunk(OopClosure* f, Chunk* c, const juint size) {
for (juint i = 0; i < size; i++) {
if (c->_data[i] != NULL) {
f->do_oop(&c->_data[i]);
}
}
}
void ClassLoaderData::ChunkedHandleList::oops_do(OopClosure* f) {
Chunk* head = (Chunk*) OrderAccess::load_ptr_acquire(&_head);
if (head != NULL) {
// Must be careful when reading size of head
oops_do_chunk(f, head, OrderAccess::load_acquire(&head->_size));
for (Chunk* c = head->_next; c != NULL; c = c->_next) {
oops_do_chunk(f, c, c->_size);
}
}
}
bool ClassLoaderData::claim() {
if (_claimed == 1) {
return false;
......@@ -111,7 +150,7 @@ void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool m
f->do_oop(&_class_loader);
_dependencies.oops_do(f);
_handles->oops_do(f);
_handles.oops_do(f);
if (klass_closure != NULL) {
classes_do(klass_closure);
}
......@@ -342,11 +381,6 @@ ClassLoaderData::~ClassLoaderData() {
_metaspace = NULL;
// release the metaspace
delete m;
// release the handles
if (_handles != NULL) {
JNIHandleBlock::release_block(_handles);
_handles = NULL;
}
}
// Clear all the JNI handles for methods
......@@ -406,15 +440,9 @@ Metaspace* ClassLoaderData::metaspace_non_null() {
return _metaspace;
}
JNIHandleBlock* ClassLoaderData::handles() const { return _handles; }
void ClassLoaderData::set_handles(JNIHandleBlock* handles) { _handles = handles; }
jobject ClassLoaderData::add_handle(Handle h) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
if (handles() == NULL) {
set_handles(JNIHandleBlock::allocate_block());
}
return handles()->allocate_handle(h());
return (jobject) _handles.add(h());
}
// Add this metadata pointer to be freed when it's safe. This is only during
......@@ -479,7 +507,6 @@ void ClassLoaderData::dump(outputStream * const out) {
p2i(class_loader() != NULL ? class_loader()->klass() : NULL), loader_name());
if (claimed()) out->print(" claimed ");
if (is_unloading()) out->print(" unloading ");
out->print(" handles " INTPTR_FORMAT, p2i(handles()));
out->cr();
if (metaspace_or_null() != NULL) {
out->print_cr("metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null()));
......
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -51,7 +51,6 @@
class ClassLoaderData;
class JNIMethodBlock;
class JNIHandleBlock;
class Metadebug;
// GC root for walking class loader data created
......@@ -145,6 +144,31 @@ class ClassLoaderData : public CHeapObj<mtClass> {
void oops_do(OopClosure* f);
};
class ChunkedHandleList VALUE_OBJ_CLASS_SPEC {
struct Chunk : public CHeapObj<mtClass> {
static const size_t CAPACITY = 32;
oop _data[CAPACITY];
volatile juint _size;
Chunk* _next;
Chunk(Chunk* c) : _next(c), _size(0) { }
};
Chunk* _head;
void oops_do_chunk(OopClosure* f, Chunk* c, const juint size);
public:
ChunkedHandleList() : _head(NULL) {}
~ChunkedHandleList();
// Only one thread at a time can add, guarded by ClassLoaderData::metaspace_lock().
// However, multiple threads can execute oops_do concurrently with add.
oop* add(oop o);
void oops_do(OopClosure* f);
};
friend class ClassLoaderDataGraph;
friend class ClassLoaderDataGraphKlassIteratorAtomic;
friend class ClassLoaderDataGraphMetaspaceIterator;
......@@ -169,7 +193,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
// Has to be an int because we cas it.
Klass* _klasses; // The classes defined by the class loader.
JNIHandleBlock* _handles; // Handles to constant pool arrays
ChunkedHandleList _handles; // Handles to constant pool arrays, etc, which
// have the same life cycle of the corresponding ClassLoader.
// These method IDs are created for the class loader and set to NULL when the
// class loader is unloaded. They are rarely freed, only for redefine classes
......@@ -196,9 +221,6 @@ class ClassLoaderData : public CHeapObj<mtClass> {
void set_metaspace(Metaspace* m) { _metaspace = m; }
JNIHandleBlock* handles() const;
void set_handles(JNIHandleBlock* handles);
Mutex* metaspace_lock() const { return _metaspace_lock; }
// GC interface.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册