8297168: Provide a bulk OopHandle release mechanism with the ServiceThread
Reviewed-by: rehn, coleenp
This commit is contained in:
parent
4a544bb0fc
commit
a6c418eaf8
@ -599,11 +599,8 @@ JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : JavaThread
|
||||
|
||||
JavaThread::~JavaThread() {
|
||||
|
||||
// Ask ServiceThread to release the OopHandles
|
||||
ServiceThread::add_oop_handle_release(_threadObj);
|
||||
ServiceThread::add_oop_handle_release(_vthread);
|
||||
ServiceThread::add_oop_handle_release(_jvmti_vthread);
|
||||
ServiceThread::add_oop_handle_release(_extentLocalCache);
|
||||
// Enqueue OopHandles for release by the service thread.
|
||||
add_oop_handles_for_release();
|
||||
|
||||
// Return the sleep event to the free list
|
||||
ParkEvent::Release(_SleepEvent);
|
||||
@ -2073,3 +2070,57 @@ void JavaThread::vm_exit_on_osthread_failure(JavaThread* thread) {
|
||||
os::native_thread_creation_failed_msg());
|
||||
}
|
||||
}
|
||||
|
||||
// Deferred OopHandle release support.
|
||||
|
||||
class OopHandleList : public CHeapObj<mtInternal> {
|
||||
static const int _count = 4;
|
||||
OopHandle _handles[_count];
|
||||
OopHandleList* _next;
|
||||
int _index;
|
||||
public:
|
||||
OopHandleList(OopHandleList* next) : _next(next), _index(0) {}
|
||||
void add(OopHandle h) {
|
||||
assert(_index < _count, "too many additions");
|
||||
_handles[_index++] = h;
|
||||
}
|
||||
~OopHandleList() {
|
||||
assert(_index == _count, "usage error");
|
||||
for (int i = 0; i < _index; i++) {
|
||||
_handles[i].release(JavaThread::thread_oop_storage());
|
||||
}
|
||||
}
|
||||
OopHandleList* next() const { return _next; }
|
||||
};
|
||||
|
||||
OopHandleList* JavaThread::_oop_handle_list = nullptr;
|
||||
|
||||
// Called by the ServiceThread to do the work of releasing
|
||||
// the OopHandles.
|
||||
void JavaThread::release_oop_handles() {
|
||||
OopHandleList* list;
|
||||
{
|
||||
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||
list = _oop_handle_list;
|
||||
_oop_handle_list = nullptr;
|
||||
}
|
||||
assert(!SafepointSynchronize::is_at_safepoint(), "cannot be called at a safepoint");
|
||||
|
||||
while (list != nullptr) {
|
||||
OopHandleList* l = list;
|
||||
list = l->next();
|
||||
delete l;
|
||||
}
|
||||
}
|
||||
|
||||
// Add our OopHandles for later release.
|
||||
void JavaThread::add_oop_handles_for_release() {
|
||||
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||
OopHandleList* new_head = new OopHandleList(_oop_handle_list);
|
||||
new_head->add(_threadObj);
|
||||
new_head->add(_vthread);
|
||||
new_head->add(_jvmti_vthread);
|
||||
new_head->add(_extentLocalCache);
|
||||
_oop_handle_list = new_head;
|
||||
Service_lock->notify_all();
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ class JvmtiSampledObjectAllocEventCollector;
|
||||
class JvmtiThreadState;
|
||||
|
||||
class Metadata;
|
||||
class OopHandleList;
|
||||
class OopStorage;
|
||||
class OSThread;
|
||||
|
||||
@ -81,9 +82,14 @@ class JavaThread: public Thread {
|
||||
friend class HandshakeState;
|
||||
friend class Continuation;
|
||||
friend class Threads;
|
||||
friend class ServiceThread; // for deferred OopHandle release access
|
||||
private:
|
||||
bool _in_asgct; // Is set when this JavaThread is handling ASGCT call
|
||||
bool _on_thread_list; // Is set when this JavaThread is added to the Threads list
|
||||
|
||||
// All references to Java objects managed via OopHandles. These
|
||||
// have to be released by the ServiceThread after the JavaThread has
|
||||
// terminated - see add_oop_handles_for_release().
|
||||
OopHandle _threadObj; // The Java level thread object
|
||||
OopHandle _vthread; // the value returned by Thread.currentThread(): the virtual thread, if mounted, otherwise _threadObj
|
||||
OopHandle _jvmti_vthread;
|
||||
@ -1168,6 +1174,20 @@ public:
|
||||
// AsyncGetCallTrace support
|
||||
inline bool in_asgct(void) {return _in_asgct;}
|
||||
inline void set_in_asgct(bool value) {_in_asgct = value;}
|
||||
|
||||
// Deferred OopHandle release support
|
||||
private:
|
||||
// List of OopHandles to be released - guarded by the Service_lock.
|
||||
static OopHandleList* _oop_handle_list;
|
||||
// Add our OopHandles to the list for the service thread to release.
|
||||
void add_oop_handles_for_release();
|
||||
// Called by the ServiceThread to release the OopHandles.
|
||||
static void release_oop_handles();
|
||||
// Called by the ServiceThread to poll if there are any OopHandles to release.
|
||||
// Called when holding the Service_lock.
|
||||
static bool has_oop_handles_to_release() {
|
||||
return _oop_handle_list != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
inline JavaThread* JavaThread::current_or_null() {
|
||||
|
@ -59,36 +59,6 @@ JvmtiDeferredEvent* ServiceThread::_jvmti_event = NULL;
|
||||
// to add this field to the per-JavaThread event queue. TODO: fix this sometime later
|
||||
JvmtiDeferredEventQueue ServiceThread::_jvmti_service_queue;
|
||||
|
||||
// Defer releasing JavaThread OopHandle to the ServiceThread
|
||||
class OopHandleList : public CHeapObj<mtInternal> {
|
||||
OopHandle _handle;
|
||||
OopHandleList* _next;
|
||||
public:
|
||||
OopHandleList(OopHandle h, OopHandleList* next) : _handle(h), _next(next) {}
|
||||
~OopHandleList() {
|
||||
_handle.release(JavaThread::thread_oop_storage());
|
||||
}
|
||||
OopHandleList* next() const { return _next; }
|
||||
};
|
||||
|
||||
static OopHandleList* _oop_handle_list = NULL;
|
||||
|
||||
static void release_oop_handles() {
|
||||
OopHandleList* list;
|
||||
{
|
||||
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||
list = _oop_handle_list;
|
||||
_oop_handle_list = NULL;
|
||||
}
|
||||
assert(!SafepointSynchronize::is_at_safepoint(), "cannot be called at a safepoint");
|
||||
|
||||
while (list != NULL) {
|
||||
OopHandleList* l = list;
|
||||
list = l->next();
|
||||
delete l;
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceThread::initialize() {
|
||||
EXCEPTION_MARK;
|
||||
|
||||
@ -152,7 +122,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
|
||||
(thread_id_table_work = ThreadIdTable::has_work()) |
|
||||
(protection_domain_table_work = ProtectionDomainCacheTable::has_work()) |
|
||||
(oopstorage_work = OopStorage::has_cleanup_work_and_reset()) |
|
||||
(oop_handles_to_release = (_oop_handle_list != NULL)) |
|
||||
(oop_handles_to_release = JavaThread::has_oop_handles_to_release()) |
|
||||
(cldg_cleanup_work = ClassLoaderDataGraph::should_clean_metaspaces_and_reset()) |
|
||||
(jvmti_tagmap_work = JvmtiTagMap::has_object_free_events_and_reset())
|
||||
) == 0) {
|
||||
@ -215,7 +185,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
|
||||
}
|
||||
|
||||
if (oop_handles_to_release) {
|
||||
release_oop_handles();
|
||||
JavaThread::release_oop_handles();
|
||||
}
|
||||
|
||||
if (cldg_cleanup_work) {
|
||||
@ -261,10 +231,3 @@ void ServiceThread::nmethods_do(CodeBlobClosure* cf) {
|
||||
_jvmti_service_queue.nmethods_do(cf);
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceThread::add_oop_handle_release(OopHandle handle) {
|
||||
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||
OopHandleList* new_head = new OopHandleList(handle, _oop_handle_list);
|
||||
_oop_handle_list = new_head;
|
||||
Service_lock->notify_all();
|
||||
}
|
||||
|
@ -52,7 +52,6 @@ class ServiceThread : public JavaThread {
|
||||
|
||||
// Add event to the service thread event queue.
|
||||
static void enqueue_deferred_event(JvmtiDeferredEvent* event);
|
||||
static void add_oop_handle_release(OopHandle handle);
|
||||
|
||||
// GC support
|
||||
void oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf);
|
||||
|
Loading…
Reference in New Issue
Block a user