mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8206423: Use locking for cleaning ResolvedMethodTable
ServiceThread is now in charge of cleaning ResolvedMethodTable entries Reviewed-by: gziemski, dholmes, coleenp
This commit is contained in:
parent
eca24bfb55
commit
4ef5590fa7
5 changed files with 31 additions and 33 deletions
|
@ -1883,7 +1883,7 @@ bool SystemDictionary::do_unloading(GCTimer* gc_timer,
|
||||||
|
|
||||||
if (do_cleaning) {
|
if (do_cleaning) {
|
||||||
GCTraceTime(Debug, gc, phases) t("ResolvedMethodTable", gc_timer);
|
GCTraceTime(Debug, gc, phases) t("ResolvedMethodTable", gc_timer);
|
||||||
ResolvedMethodTable::unlink();
|
ResolvedMethodTable::trigger_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
return unloading_occurred;
|
return unloading_occurred;
|
||||||
|
|
|
@ -83,7 +83,6 @@
|
||||||
#include "oops/access.inline.hpp"
|
#include "oops/access.inline.hpp"
|
||||||
#include "oops/compressedOops.inline.hpp"
|
#include "oops/compressedOops.inline.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "prims/resolvedMethodTable.hpp"
|
|
||||||
#include "runtime/atomic.hpp"
|
#include "runtime/atomic.hpp"
|
||||||
#include "runtime/flags/flagSetting.hpp"
|
#include "runtime/flags/flagSetting.hpp"
|
||||||
#include "runtime/handles.inline.hpp"
|
#include "runtime/handles.inline.hpp"
|
||||||
|
@ -3532,28 +3531,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class G1ResolvedMethodCleaningTask : public StackObj {
|
|
||||||
volatile int _resolved_method_task_claimed;
|
|
||||||
public:
|
|
||||||
G1ResolvedMethodCleaningTask() :
|
|
||||||
_resolved_method_task_claimed(0) {}
|
|
||||||
|
|
||||||
bool claim_resolved_method_task() {
|
|
||||||
if (_resolved_method_task_claimed) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return Atomic::cmpxchg(1, &_resolved_method_task_claimed, 0) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// These aren't big, one thread can do it all.
|
|
||||||
void work() {
|
|
||||||
if (claim_resolved_method_task()) {
|
|
||||||
ResolvedMethodTable::unlink();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// To minimize the remark pause times, the tasks below are done in parallel.
|
// To minimize the remark pause times, the tasks below are done in parallel.
|
||||||
class G1ParallelCleaningTask : public AbstractGangTask {
|
class G1ParallelCleaningTask : public AbstractGangTask {
|
||||||
private:
|
private:
|
||||||
|
@ -3561,7 +3538,6 @@ private:
|
||||||
G1StringCleaningTask _string_task;
|
G1StringCleaningTask _string_task;
|
||||||
G1CodeCacheUnloadingTask _code_cache_task;
|
G1CodeCacheUnloadingTask _code_cache_task;
|
||||||
G1KlassCleaningTask _klass_cleaning_task;
|
G1KlassCleaningTask _klass_cleaning_task;
|
||||||
G1ResolvedMethodCleaningTask _resolved_method_cleaning_task;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// The constructor is run in the VMThread.
|
// The constructor is run in the VMThread.
|
||||||
|
@ -3570,8 +3546,7 @@ public:
|
||||||
_unloading_occurred(unloading_occurred),
|
_unloading_occurred(unloading_occurred),
|
||||||
_string_task(is_alive, true, G1StringDedup::is_enabled()),
|
_string_task(is_alive, true, G1StringDedup::is_enabled()),
|
||||||
_code_cache_task(num_workers, is_alive, unloading_occurred),
|
_code_cache_task(num_workers, is_alive, unloading_occurred),
|
||||||
_klass_cleaning_task(),
|
_klass_cleaning_task() {
|
||||||
_resolved_method_cleaning_task() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The parallel work done by all worker threads.
|
// The parallel work done by all worker threads.
|
||||||
|
@ -3585,9 +3560,6 @@ public:
|
||||||
// Clean the Strings.
|
// Clean the Strings.
|
||||||
_string_task.work(worker_id);
|
_string_task.work(worker_id);
|
||||||
|
|
||||||
// Clean unreferenced things in the ResolvedMethodTable
|
|
||||||
_resolved_method_cleaning_task.work();
|
|
||||||
|
|
||||||
// Wait for all workers to finish the first code cache cleaning pass.
|
// Wait for all workers to finish the first code cache cleaning pass.
|
||||||
_code_cache_task.barrier_wait(worker_id);
|
_code_cache_task.barrier_wait(worker_id);
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ ResolvedMethodTable::ResolvedMethodTable()
|
||||||
: Hashtable<ClassLoaderWeakHandle, mtClass>(_table_size, sizeof(ResolvedMethodEntry)) { }
|
: Hashtable<ClassLoaderWeakHandle, mtClass>(_table_size, sizeof(ResolvedMethodEntry)) { }
|
||||||
|
|
||||||
oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) {
|
oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) {
|
||||||
|
assert_locked_or_safepoint(ResolvedMethodTable_lock);
|
||||||
for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) {
|
for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) {
|
||||||
if (p->hash() == hash) {
|
if (p->hash() == hash) {
|
||||||
|
|
||||||
|
@ -114,6 +115,7 @@ oop ResolvedMethodTable::basic_add(Method* method, Handle rmethod_name) {
|
||||||
ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL;
|
ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL;
|
||||||
|
|
||||||
oop ResolvedMethodTable::find_method(Method* method) {
|
oop ResolvedMethodTable::find_method(Method* method) {
|
||||||
|
MutexLocker ml(ResolvedMethodTable_lock);
|
||||||
oop entry = _the_table->lookup(method);
|
oop entry = _the_table->lookup(method);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
@ -144,9 +146,19 @@ oop ResolvedMethodTable::add_method(Handle resolved_method_name) {
|
||||||
int ResolvedMethodTable::_oops_removed = 0;
|
int ResolvedMethodTable::_oops_removed = 0;
|
||||||
int ResolvedMethodTable::_oops_counted = 0;
|
int ResolvedMethodTable::_oops_counted = 0;
|
||||||
|
|
||||||
|
// There are no dead entries at start
|
||||||
|
bool ResolvedMethodTable::_dead_entries = false;
|
||||||
|
|
||||||
|
void ResolvedMethodTable::trigger_cleanup() {
|
||||||
|
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
_dead_entries = true;
|
||||||
|
Service_lock->notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
// Serially invoke removed unused oops from the table.
|
// Serially invoke removed unused oops from the table.
|
||||||
// This is done late during GC.
|
// This is done by the ServiceThread after being notified on class unloading
|
||||||
void ResolvedMethodTable::unlink() {
|
void ResolvedMethodTable::unlink() {
|
||||||
|
MutexLocker ml(ResolvedMethodTable_lock);
|
||||||
_oops_removed = 0;
|
_oops_removed = 0;
|
||||||
_oops_counted = 0;
|
_oops_counted = 0;
|
||||||
for (int i = 0; i < _the_table->table_size(); ++i) {
|
for (int i = 0; i < _the_table->table_size(); ++i) {
|
||||||
|
@ -173,10 +185,12 @@ void ResolvedMethodTable::unlink() {
|
||||||
}
|
}
|
||||||
log_debug(membername, table) ("ResolvedMethod entries counted %d removed %d",
|
log_debug(membername, table) ("ResolvedMethod entries counted %d removed %d",
|
||||||
_oops_counted, _oops_removed);
|
_oops_counted, _oops_removed);
|
||||||
|
_dead_entries = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void ResolvedMethodTable::print() {
|
void ResolvedMethodTable::print() {
|
||||||
|
MutexLocker ml(ResolvedMethodTable_lock);
|
||||||
for (int i = 0; i < table_size(); ++i) {
|
for (int i = 0; i < table_size(); ++i) {
|
||||||
ResolvedMethodEntry* entry = bucket(i);
|
ResolvedMethodEntry* entry = bucket(i);
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
|
|
|
@ -59,6 +59,8 @@ class ResolvedMethodTable : public Hashtable<ClassLoaderWeakHandle, mtClass> {
|
||||||
static int _oops_removed;
|
static int _oops_removed;
|
||||||
static int _oops_counted;
|
static int _oops_counted;
|
||||||
|
|
||||||
|
static bool _dead_entries;
|
||||||
|
|
||||||
static ResolvedMethodTable* _the_table;
|
static ResolvedMethodTable* _the_table;
|
||||||
private:
|
private:
|
||||||
ResolvedMethodEntry* bucket(int i) {
|
ResolvedMethodEntry* bucket(int i) {
|
||||||
|
@ -90,6 +92,9 @@ public:
|
||||||
static oop find_method(Method* method);
|
static oop find_method(Method* method);
|
||||||
static oop add_method(Handle rmethod_name);
|
static oop add_method(Handle rmethod_name);
|
||||||
|
|
||||||
|
static bool has_work() { return _dead_entries; }
|
||||||
|
static void trigger_cleanup();
|
||||||
|
|
||||||
#if INCLUDE_JVMTI
|
#if INCLUDE_JVMTI
|
||||||
// It is called at safepoint only for RedefineClasses
|
// It is called at safepoint only for RedefineClasses
|
||||||
static void adjust_method_entries(bool * trace_name_printed);
|
static void adjust_method_entries(bool * trace_name_printed);
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "runtime/mutexLocker.hpp"
|
#include "runtime/mutexLocker.hpp"
|
||||||
#include "runtime/os.hpp"
|
#include "runtime/os.hpp"
|
||||||
#include "prims/jvmtiImpl.hpp"
|
#include "prims/jvmtiImpl.hpp"
|
||||||
|
#include "prims/resolvedMethodTable.hpp"
|
||||||
#include "services/diagnosticArgument.hpp"
|
#include "services/diagnosticArgument.hpp"
|
||||||
#include "services/diagnosticFramework.hpp"
|
#include "services/diagnosticFramework.hpp"
|
||||||
#include "services/gcNotifier.hpp"
|
#include "services/gcNotifier.hpp"
|
||||||
|
@ -86,6 +87,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
|
||||||
bool acs_notify = false;
|
bool acs_notify = false;
|
||||||
bool stringtable_work = false;
|
bool stringtable_work = false;
|
||||||
bool symboltable_work = false;
|
bool symboltable_work = false;
|
||||||
|
bool resolved_method_table_work = false;
|
||||||
JvmtiDeferredEvent jvmti_event;
|
JvmtiDeferredEvent jvmti_event;
|
||||||
{
|
{
|
||||||
// Need state transition ThreadBlockInVM so that this thread
|
// Need state transition ThreadBlockInVM so that this thread
|
||||||
|
@ -104,7 +106,8 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
|
||||||
!(has_gc_notification_event = GCNotifier::has_event()) &&
|
!(has_gc_notification_event = GCNotifier::has_event()) &&
|
||||||
!(has_dcmd_notification_event = DCmdFactory::has_pending_jmx_notification()) &&
|
!(has_dcmd_notification_event = DCmdFactory::has_pending_jmx_notification()) &&
|
||||||
!(stringtable_work = StringTable::has_work()) &&
|
!(stringtable_work = StringTable::has_work()) &&
|
||||||
!(symboltable_work = SymbolTable::has_work())) {
|
!(symboltable_work = SymbolTable::has_work()) &&
|
||||||
|
!(resolved_method_table_work = ResolvedMethodTable::has_work())) {
|
||||||
// wait until one of the sensors has pending requests, or there is a
|
// wait until one of the sensors has pending requests, or there is a
|
||||||
// pending JVMTI event or JMX GC notification to post
|
// pending JVMTI event or JMX GC notification to post
|
||||||
Service_lock->wait(Mutex::_no_safepoint_check_flag);
|
Service_lock->wait(Mutex::_no_safepoint_check_flag);
|
||||||
|
@ -132,12 +135,16 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(has_gc_notification_event) {
|
if(has_gc_notification_event) {
|
||||||
GCNotifier::sendNotification(CHECK);
|
GCNotifier::sendNotification(CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(has_dcmd_notification_event) {
|
if(has_dcmd_notification_event) {
|
||||||
DCmdFactory::send_notification(CHECK);
|
DCmdFactory::send_notification(CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resolved_method_table_work) {
|
||||||
|
ResolvedMethodTable::unlink();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue