java 垃圾收集通知?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2057792/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 19:11:03  来源:igfitidea点击:

Garbage collection notification?

javagarbage-collection

提问by Ted Graham

I'd like to register a callback with the JVM so I know when garbage collection is happening. Is there any way to do this?

我想向 JVM 注册一个回调,以便我知道垃圾收集何时发生。有没有办法做到这一点?

EDIT: I want to do this so I can log out when garbage collection happens in my application log, so I can see if it correlates to problems I'm seeing. Turning on -Xloggc is helpful, but it is a little tricky to integrate the times from the GC log (which use seconds since app start) into my main application log.

编辑:我想这样做,这样我就可以在应用程序日志中发生垃圾收集时注销,这样我就可以查看它是否与我看到的问题相关。打开 -Xloggc 很有帮助,但将 GC 日志(使用自应用程序启动后的秒数)中的时间整合到我的主应用程序日志中有点棘手。

EDIT April 2012: As of Java7u4, you can get notifications from the GarbageCollectorMXBean (a nice example).

2012 年 4 月编辑:从 Java7u4 开始,您可以从 GarbageCollectorMXBean 获得通知(一个很好的例子)。

采纳答案by Ted Graham

回答by Pascal Thivent

I think that the standard way is to use the JVM Tool Interface (JVM TI)to write an agent with a GC start callback and to log the time from it (see GetTime). Note that a Garbage Collection Start eventis sent for full GCs only.

我认为标准方法是使用JVM 工具接口 (JVM TI)编写带有 GC 启动回调的代理并从中记录时间(请参阅GetTime)。请注意,垃圾收集开始事件仅针对完整 GC 发送。

Sample JVM TI agents is available in the demo directory of the JDK 5.0 or the JDK 6 download. The tech article The JVM Tool Interface (JVM TI): How VM Agents Workis another very good resource. Also have a look at Creating a Debugging and Profiling Agent with JVMTI.

示例 JVM TI 代理位于 JDK 5.0 或 JDK 6 下载的演示目录中。技术文章The JVM Tool Interface (JVM TI): How VM Agents Work是另一个非常好的资源。另请查看使用 JVMTI 创建调试和分析代理

回答by Eric

Java code sampleusing the GarbageCollectorMXBeanreferred to in the accepted answer:

使用GarbageCollectorMXBean已接受答案中引用的Java 代码示例

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

site that has detailed sample code that uses the GarbageCollectorMXBean.

具有使用GarbageCollectorMXBean.

回答by Adam Goode

It looks like you could use the MemoryPoolMXBean and set the collection usage threshold to 1. This should give you a notification any time the gc runs and there is still at least a byte of memory in use.

看起来您可以使用 MemoryPoolMXBean 并将集合使用阈值设置为 1。这应该会在 gc 运行并且仍然至少有一个字节的内存正在使用时给您一个通知。

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/management/MemoryPoolMXBean.html

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/management/MemoryPoolMXBean.html

It looks like this doesn't work with all garbage collectors, though.

不过,这似乎不适用于所有垃圾收集器。

回答by Paul Anderson

When receiving the JVMTI event for Garbage Collection the JVM is technically stopped so it's unable to call back a Java listener via JNI.... this agent prints out the time at GC start and finish with a higher resolution than the verbose GC on the Sun JVM.

当接收到垃圾收集的 JVMTI 事件时,JVM 在技术上被停止,因此它无法通过 JNI 回调 Java 侦听器......该代理以比 Sun 上的详细 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;
}

回答by R.daneel.olivaw

I know this is very late but I hope it might help someone someday.

我知道这已经很晚了,但我希望有一天它可以帮助某人。

You can receive such events this by using the using the library that i am developing called gcRadar. It provides information about exactly when an object was garbage collected.

您可以使用我正在开发的名为gcRadar的库来接收此类事件。它提供有关对象被垃圾收集的确切时间的信息。

Any suggestions for improvements in the library are welcome.

欢迎任何改进图书馆的建议。

回答by user533933

Another use case for getting impending GC notifications: if your app is load balanced then you can then notify the load balancer to take your node out of the pool when a GC is about to start to that it does not receive requests that would have to wait for a full GC to get dealt with.

获取即将发生的 GC 通知的另一个用例:如果您的应用是负载平衡的,那么您可以通知负载平衡器在 GC 即将开始时将您的节点从池中取出,因为它不会收到必须等待的请求处理完整的 GC。

That doesn't help in-flight requests that arrived just before the GC kicked in but, in my case at least, most requests are subsecond and major GCs are 5-10s, every few minutes. We can tweak the NewGen ratios etc but the general point still applies: major GC may be much longer than typical response times so you may want to premptivelystop a node starting a major GC from receiving requests.

这对在 GC 开始之前到达的正在进行的请求没有帮助,但至少在我的情况下,大多数请求是亚秒级的,主要 GC 是 5-10 秒,每隔几分钟。我们可以调整 NewGen 比率等,但一般观点仍然适用:主要 GC 可能比典型的响应时间长得多,因此您可能希望预先停止启动主要 GC 的节点接收请求。

When GC is over, a thread in the JVM can send a notification to the load balancer to let it know its back in business or the LB can rely on its usual keepalive.

当 GC 结束时,JVM 中的一个线程可以向负载均衡器发送通知,让它知道它恢复了业务,或者 LB 可以依赖其通常的 keepalive。

回答by Joshua Davis

Regarding -Xloggc: As of jdk1.6 update 4 you can get the Sun/Oracle JVM to print out the date and time using -XX:+PrintGCDateStamps. This makes the logs muchmore useful, especially if you add a log scanner / monitor that can notify you of any GC issues.

关于-Xloggc:从 jdk1.6 update 4 开始,您可以让 Sun/Oracle JVM 使用 -XX:+PrintGCDateStamps. 这使得原木太大更加有用,特别是如果你添加日志扫描仪/监视器,可以通知您任何GC的问题。

回答by Thorbj?rn Ravn Andersen

There is no standard way for your own program to get information from the JVM about garbage collection. Any such API is vendor specific.

您自己的程序没有标准方法可以从 JVM 获取有关垃圾收集的信息。任何此类 API 都是特定于供应商的。

Why is the facility you found insufficient?

为什么您发现的设施不足?

回答by Kaleb Brasee

There's an interesting article on Javalobbydiscussing one method of doing this.

Javalobby 上有一篇有趣的文章讨论了一种方法。