8297168: Provide a bulk OopHandle release mechanism with the ServiceThread

Reviewed-by: rehn, coleenp
This commit is contained in:
David Holmes 2022-11-22 21:57:33 +00:00
parent 4a544bb0fc
commit a6c418eaf8
4 changed files with 78 additions and 45 deletions

View File

@ -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();
}

View File

@ -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() {

View File

@ -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();
}

View File

@ -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);