GC notifications are sent to the ServiceThread, as shown in the Groovy shell example in this gist. The ServiceThread is a JavaThread, so it can execute Java code.
To see GC notification in action, refer to a conversation in hotspot-gc-dev. Another thread of interest is the discussions on 7110173: GCNotifier::pushNotification publishes stale data.
In the HotSpot VM, GC notifications are pushed with GCNotifier::pushNotification()
, in GCMemoryManager::gc_end()
, which is in turn called by MemoryService::gc_end()
.
hotspot/src/share/vm/runtime/serviceThread.cpp
void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
while (true) {
bool sensors_changed = false;
bool has_jvmti_events = false;
bool has_gc_notification_event = false;
JvmtiDeferredEvent jvmti_event;
{
// Need state transition ThreadBlockInVM so that this thread
// will be handled by safepoint correctly when this thread is
// notified at a safepoint.
// This ThreadBlockInVM object is not also considered to be
// suspend-equivalent because ServiceThread is not visible to
// external suspension.
ThreadBlockInVM tbivm(jt);
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
while (!(sensors_changed = LowMemoryDetector::has_pending_requests()) &&
!(has_jvmti_events = JvmtiDeferredEventQueue::has_events()) &&
!(has_gc_notification_event = GCNotifier::has_event())) {
// wait until one of the sensors has pending requests, or there is a
// pending JVMTI event or JMX GC notification to post
Service_lock->wait(Mutex::_no_safepoint_check_flag);
}
if (has_jvmti_events) {
jvmti_event = JvmtiDeferredEventQueue::dequeue();
}
}
if (has_jvmti_events) {
jvmti_event.post();
}
if (sensors_changed) {
LowMemoryDetector::process_sensor_changes(jt);
}
if(has_gc_notification_event) {
GCNotifier::sendNotification(CHECK);
}
}
}
hotspot/src/share/vm/services/gcNotifier.cpp
void GCNotifier::sendNotification(TRAPS) {
ResourceMark rm(THREAD);
GCNotificationRequest *request = getRequest();
if(request != NULL) {
Handle objGcInfo = createGcInfo(request->gcManager,request->gcStatInfo,THREAD);
Handle objName = java_lang_String::create_from_platform_dependent_str(request->gcManager->name(), CHECK);
Handle objAction = java_lang_String::create_from_platform_dependent_str(request->gcAction, CHECK);
Handle objCause = java_lang_String::create_from_platform_dependent_str(request->gcCause, CHECK);
klassOop k = Management::sun_management_GarbageCollectorImpl_klass(CHECK);
instanceKlassHandle gc_mbean_klass (THREAD, k);
instanceOop gc_mbean = request->gcManager->get_memory_manager_instance(THREAD);
instanceHandle gc_mbean_h(THREAD, gc_mbean);
if (!gc_mbean_h->is_a(k)) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"This GCMemoryManager doesn't have a GarbageCollectorMXBean");
}
JavaValue result(T_VOID);
JavaCallArguments args(gc_mbean_h);
args.push_long(request->timestamp);
args.push_oop(objName);
args.push_oop(objAction);
args.push_oop(objCause);
args.push_oop(objGcInfo);
JavaCalls::call_virtual(&result,
gc_mbean_klass,
vmSymbols::createGCNotification_name(),
vmSymbols::createGCNotification_signature(),
&args,
CHECK);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
}
delete request;
}
}
package sun.management;
// ...
/**
* Implementation class for the garbage collector.
* Standard and committed hotspot-specific metrics if any.
*
* ManagementFactory.getGarbageCollectorMXBeans() returns a list
* of instances of this class.
*/
class GarbageCollectorImpl extends MemoryManagerImpl
implements GarbageCollectorMXBean {
//...
void createGCNotification(long timestamp,
String gcName,
String gcAction,
String gcCause,
GcInfo gcInfo) {
if (!hasListeners()) {
return;
}
Notification notif = new Notification(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION,
getObjectName(),
getNextSeqNumber(),
timestamp,
gcName);
GarbageCollectionNotificationInfo info =
new GarbageCollectionNotificationInfo(gcName,
gcAction,
gcCause,
gcInfo);
CompositeData cd =
GarbageCollectionNotifInfoCompositeData.toCompositeData(info);
notif.setUserData(cd);
sendNotification(notif);
}
package sun.management;
// ...
class MemoryManagerImpl extends NotificationEmitterSupport
implements MemoryManagerMXBean
package sun.management;
// ...
/**
* Abstract helper class for notification emitter support.
*/
abstract class NotificationEmitterSupport implements NotificationEmitter {
// ...
void sendNotification(Notification notification) {
if (notification == null) {
return;
}
List<ListenerInfo> currentList;
synchronized (listenerLock) {
currentList = listenerList;
}
final int size = currentList.size();
for (int i = 0; i < size; i++) {
ListenerInfo li = (ListenerInfo) currentList.get(i);
if (li.filter == null
|| li.filter.isNotificationEnabled(notification)) {
try {
li.listener.handleNotification(notification, li.handback);
} catch (Exception e) {
e.printStackTrace();
throw new AssertionError("Error in invoking listener");
}
}
}
}