Уведомление о сборке мусора? - PullRequest
35 голосов
/ 13 января 2010

Я хотел бы зарегистрировать обратный вызов в JVM, чтобы я знал, когда происходит сборка мусора. Есть ли способ сделать это?

РЕДАКТИРОВАТЬ: я хочу сделать это, чтобы я мог выйти из системы, когда сборка мусора происходит в моем журнале приложений, чтобы я мог видеть, соответствует ли это проблемам, которые я вижу. Включение -Xloggc полезно, но немного сложнее интегрировать времена из журнала GC (которые используют секунды с момента запуска приложения) в мой основной журнал приложения.

РЕДАКТИРОВАТЬ Апрель 2012: Начиная с Java7u4, вы можете получать уведомления от GarbageCollectorMXBean (хороший пример ).

Ответы [ 11 ]

18 голосов
/ 30 апреля 2012

Начиная с Java7u4, вы можете получать уведомления от GarbageCollectorMXBean. Смотри http://docs.oracle.com/javase/7/docs/jre/api/management/extension/com/sun/management/GarbageCollectionNotificationInfo.html

10 голосов
/ 13 января 2010

Я думаю, что стандартным способом является использование интерфейса инструментов JVM (JVM TI) для написания агента с обратным вызовом запуска GC и для регистрации времени из него (см. GetTime ). Обратите внимание, что Событие запуска сбора мусора отправляется только для полных ГХ.

Образцы агентов JVM TI доступны в демонстрационном каталоге JDK 5.0 или в загрузке JDK 6. Техническая статья Интерфейс инструментов JVM (JVM TI): как работают агенты VM - еще один очень хороший ресурс. Также взгляните на Создание агента отладки и профилирования с JVMTI .

7 голосов
/ 01 октября 2016

Пример кода Java с использованием GarbageCollectorMXBean, указанного в принятом ответе:

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

сайт с подробным примером кода, который использует GarbageCollectorMXBean.

3 голосов
/ 13 января 2010

Похоже, вы могли бы использовать MemoryPoolMXBean и установить порог использования коллекции равным 1. Это должно дать вам уведомление всякий раз, когда запускается gc, и все еще используется хотя бы один байт памяти.

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

Похоже, что это работает не со всеми сборщиками мусора.

2 голосов
/ 13 декабря 2013

Я знаю, что уже очень поздно, но я надеюсь, что когда-нибудь это может кому-нибудь помочь.

Вы можете получить такие события, используя используемую мной библиотеку под названием gcRadar . Он предоставляет информацию о том, когда именно был собран объект.

Любые предложения по улучшению библиотеки приветствуются.

2 голосов
/ 05 февраля 2012

Другой вариант использования для получения предстоящих уведомлений GC: если ваше приложение сбалансировано по нагрузке, тогда вы можете уведомить балансировщик нагрузки, чтобы вывести ваш узел из пула, когда GC собирается начать, что он не получает запросы, которые могли бы придется ждать полного GC, чтобы иметь дело с.

Это не помогает запросам в полете, поступившим незадолго до запуска GC, но, по крайней мере, в моем случае большинство запросов выполняются вторыми секундами, а основные GC - 5-10 с каждые несколько минут. Мы можем настроить отношения NewGen и т. Д., Но общий принцип по-прежнему применим: основной GC может быть намного длиннее, чем обычное время ответа, поэтому вы можете с опережением остановить узел, запускающий основной GC, от получения запросов.

Когда GC заканчивается, поток в JVM может отправлять уведомление балансировщику нагрузки, чтобы он знал, что вернулся в бизнес, или LB может полагаться на свой обычный keepalive.

2 голосов
/ 13 февраля 2011

При получении события JVMTI для сборки мусора JVM технически останавливается, поэтому он не может вызвать обратный вызов слушателя Java через JNI .... этот агент печатает время при запуске и завершении GC с более высоким разрешением, чем у подробного GC на Солнце JVM.

#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;
}
1 голос
/ 25 января 2012

Относительно -Xloggc: начиная с jdk1.6, обновление 4, вы можете заставить JVM Sun / Oracle распечатать дату и время, используя -XX:+PrintGCDateStamps. Это делает журналы намного более полезными, особенно если вы добавляете сканер / монитор журналов, который может уведомлять вас о любых проблемах с GC.

1 голос
/ 13 января 2010

Для вашей собственной программы не существует стандартного способа получения информации от JVM о сборке мусора. Любой такой API зависит от поставщика.

Почему учреждение, которое вы нашли недостаточным?

1 голос
/ 13 января 2010

В Javalobby есть интересная статья , в которой обсуждается один из способов сделать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...