Java 垃圾收集通知?
我想在JVM中注册一个回调,以便知道垃圾回收何时发生。有没有办法做到这一点 编辑:我想这样做,以便在应用程序日志中发生垃圾收集时可以注销,以便查看它是否与我看到的问题相关。启用-Xloggc是有帮助的,但是要将GC日志中的时间(从应用程序启动开始使用秒数)集成到我的主应用程序日志中有点棘手Java 垃圾收集通知?,java,garbage-collection,Java,Garbage Collection,我想在JVM中注册一个回调,以便知道垃圾回收何时发生。有没有办法做到这一点 编辑:我想这样做,以便在应用程序日志中发生垃圾收集时可以注销,以便查看它是否与我看到的问题相关。启用-Xloggc是有帮助的,但是要将GC日志中的时间(从应用程序启动开始使用秒数)集成到我的主应用程序日志中有点棘手 2012年4月编辑:从Java7u4开始,您可以从GarbageCollectorMXBean(一个nice)获得通知。有一种方法可以做到这一点。看起来您可以使用MemoryPoolMXBean并将收集使用阈
2012年4月编辑:从Java7u4开始,您可以从GarbageCollectorMXBean(一个nice)获得通知。有一种方法可以做到这一点。看起来您可以使用MemoryPoolMXBean并将收集使用阈值设置为1。当gc运行并且仍有至少一个字节的内存在使用时,这应该会给您一个通知
不过,这似乎并不适用于所有垃圾收集器。您自己的程序没有标准的方法从JVM获取有关垃圾收集的信息。任何此类API都是特定于供应商的
为什么您发现设施不足 如果您将此作为诊断工具,我建议将应用程序日志重定向到StdOut,然后将StdOut和StdErr重定向到文件中。这将为您提供JVM日志记录的详细信息,而不会强迫您更改应用程序代码。我认为标准的方法是使用编写带有GC启动回调的代理,并记录从它开始的时间(请参阅)。请注意,仅针对完整地面军事系统发送
jdk5.0或jdk6下载的demo目录中提供了示例jvmti代理。科技文章是另一个很好的资源。也来看看 当接收到用于垃圾收集的JVMTI事件时,JVM在技术上已停止,因此无法通过JNI回调Java侦听器。。。。此代理以比Sun JVM上的详细GC更高的分辨率打印GC开始和结束时的时间
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include "jvmti.h"
void printGCTime(const char* type) {
struct timeval tv;
gettimeofday(&tv, NULL);
struct tm localTime;
localtime_r(&tv.tv_sec, &localTime);
char *startTime = calloc(1, 128);
strftime(startTime, (size_t) 128, "%a %b %d %Y %H:%M:%S", &localTime);
fprintf(stderr, "GC %s: %s.%06d\n", type, startTime, (int)tv.tv_usec );
fflush(stderr);
if(startTime) free(startTime);
}
void JNICALL
garbageCollectionStart(jvmtiEnv *jvmti_env) {
printGCTime("Start ");
}
void JNICALL
garbageCollectionFinish(jvmtiEnv *jvmti_env) {
printGCTime("Finish");
}
JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM * jvm, char *options, void *reserved)
{
jvmtiEnv *jvmti_env;
jint returnCode = (*jvm)->GetEnv(jvm, (void **) &jvmti_env,
JVMTI_VERSION_1_0);
if (returnCode != JNI_OK)
{
fprintf(stderr,
"The version of JVMTI requested (1.0) is not supported by this JVM.\n");
return JVMTI_ERROR_UNSUPPORTED_VERSION;
}
jvmtiCapabilities *requiredCapabilities;
requiredCapabilities = (jvmtiCapabilities*) calloc(1, sizeof(jvmtiCapabilities));
if (!requiredCapabilities)
{
fprintf(stderr, "Unable to allocate memory\n");
return JVMTI_ERROR_OUT_OF_MEMORY;
}
requiredCapabilities->can_generate_garbage_collection_events = 1;
if (returnCode != JNI_OK)
{
fprintf(stderr, "C:\tJVM does not have the required capabilities (%d)\n",
returnCode);
exit(-1);
}
returnCode = (*jvmti_env)->AddCapabilities(jvmti_env, requiredCapabilities);
jvmtiEventCallbacks *eventCallbacks;
eventCallbacks = calloc(1, sizeof(jvmtiEventCallbacks));
if (!eventCallbacks)
{
fprintf(stderr, "Unable to allocate memory\n");
return JVMTI_ERROR_OUT_OF_MEMORY;
}
eventCallbacks->GarbageCollectionStart = &garbageCollectionStart;
eventCallbacks->GarbageCollectionFinish = &garbageCollectionFinish;
returnCode = (*jvmti_env)->SetEventCallbacks(jvmti_env,
eventCallbacks, (jint) sizeof(*eventCallbacks));
if (returnCode != JNI_OK)
{
fprintf(stderr, "C:\tError setting event callbacks (%d)\n",
returnCode);
exit(-1);
}
returnCode = (*jvmti_env)->SetEventNotificationMode(
jvmti_env, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, (jthread) NULL);
if (returnCode != JNI_OK)
{
fprintf(
stderr,
"C:\tJVM does not have the required capabilities, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START (%d)\n",
returnCode);
exit(-1);
}
returnCode = (*jvmti_env)->SetEventNotificationMode(
jvmti_env, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, (jthread) NULL);
if (returnCode != JNI_OK)
{
fprintf(
stderr,
"C:\tJVM does not have the required capabilities, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH (%d)\n",
returnCode);
exit(-1);
}
if(requiredCapabilities) free(requiredCapabilities);
if(eventCallbacks) free(eventCallbacks);
return JVMTI_ERROR_NONE;
}
#包括
#包括
#包括
#包括“jvmti.h”
无效打印时间(常量字符*类型){
结构时间值电视;
gettimeofday(&tv,NULL);
struct tm localTime;
localtime\r(&tv.tv\u秒,&localtime);
char*startTime=calloc(1128);
strftime(开始时间,(大小)128,“%a%b%d%Y%H:%M:%S”,&localTime);
fprintf(stderr,“GC%s:%s.%06d\n”,类型,开始时间,(int)tv.tv\u usec);
fflush(stderr);
如果(开始时间)空闲(开始时间);
}
无效JNICALL
垃圾收集启动(jvmtiEnv*jvmti_环境){
打印时间(“开始”);
}
无效JNICALL
垃圾收集整理(jvmtiEnv*jvmti_环境){
打印时间(“完成”);
}
JNIEXPORT jint JNICALL
代理加载(JavaVM*jvm,char*选项,void*保留)
{
jvmtiEnv*jvmti_环境;
jint returnCode=(*jvm)->GetEnv(jvm,(void**)和jvmti_env,
JVMTI_版本(1_0);
如果(返回代码!=JNI_OK)
{
fprintf(标准,
“此JVM不支持请求的JVMTI版本(1.0)。\n”);
返回JVMTI\u错误\u不支持的\u版本;
}
JVM能力*所需能力;
requiredCapabilities=(JVMTICAabilities*)calloc(1,sizeof(JVMTICAabilities));
如果(!requiredCapabilities)
{
fprintf(stderr,“无法分配内存”);
返回JVMTI_ERROR_OUT_OF_内存;
}
requiredCapabilities->can_generate_garbage_collection_events=1;
如果(返回代码!=JNI_OK)
{
fprintf(stderr,“C:\tJVM没有所需的功能(%d)\n”,
返回代码);
出口(-1);
}
returnCode=(*jvmti_env)->AddCapabilities(jvmti_env,requiredCapabilities);
jvmtiEventCallbacks*事件回调;
eventCallbacks=calloc(1,sizeof(jvmtiEventCallbacks));
如果(!eventCallbacks)
{
fprintf(stderr,“无法分配内存”);
返回JVMTI_ERROR_OUT_OF_内存;
}
eventCallbacks->GarbageCollectionStart=&GarbageCollectionStart;
eventCallbacks->GarbageCollectionFinish=&GarbageCollectionFinish;
returnCode=(*jvmti_env)->SetEventCallbacks(jvmti_env,
eventCallbacks,(jint)sizeof(*eventCallbacks));
如果(返回代码!=JNI_OK)
{
fprintf(stderr,“C:\tError设置事件回调(%d)\n”,
返回代码);
出口(-1);
}
returnCode=(*jvmti_env)->SetEventNotificationMode(
jvmti_env、jvmti_ENABLE、jvmti_EVENT_GARBAGE_COLLECTION_START、(jthread)NULL);
如果(返回代码!=JNI_OK)
{
fprintf(
斯特德尔,
“C:\tJVM没有所需的功能、JVMTI\u启用、JVMTI\u事件\u垃圾收集\u启动(%d)\n”,
返回代码);
出口(-1);
}
returnCode=(*jvmti_env)->SetEventNotificationMode(
jvmti_env、jvmti_ENABLE、jvmti_EVENT_GARBAGE_COLLECTION_FINISH(jthread)NULL);
如果(返回代码!=JNI_OK)
{
fprintf(
斯特德尔,
“C:\tJVM没有所需的功能、JVMTI\u启用、JVMTI\u事件\u垃圾收集\u完成(%d)\n”,
返回代码);
出口(-1);
}
如果(要求的能力)免费(要求的能力);
if(eventCallbacks)free(eventCallbacks);
返回JVMTI\u错误\u无;
}
关于-Xloggc
:从jdk1.6更新4开始,您可以让Sun/Oracle JVM使用-XX:+printgcdatastamps
打印日期和时间。这使得日志更加有用,特别是如果您添加了日志扫描程序/监视器,可以通知您任何GC问题
static
{
// notification listener. is notified whenever a gc finishes.
NotificationListener notificationListener = new NotificationListener()
{
@Override
public void handleNotification(Notification notification,Object handback)
{
if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION))
{
// extract garbage collection information from notification.
GarbageCollectionNotificationInfo gcInfo = GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData());
// access garbage collection information...
}
}
};
// register our listener with all gc beans
for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans())
{
NotificationEmitter emitter = (NotificationEmitter) gcBean;
emitter.addNotificationListener(notificationListener,null,null);
}
}