Как узнать, кто вызывает System.gc()?

В работающей системе мы видим много «Полный сборщик мусора (система)», что указывает на то, что кто-то запускает System.gc().

Есть ли способ узнать, где в коде это происходит?

Я просмотрел все доступные источники, но не нашел ничего подозрительного, поэтому он должен быть где-то, возможно, в другом приложении, работающем в том же контейнере, или в самом контейнере.


person Aaron Digulla    schedule 29.07.2011    source источник
comment
Простое решение: запустите приложение в режиме отладки и поставьте точку останова метода на System.gc()Runtime.gc() на всякий случай).   -  person Joachim Sauer    schedule 29.07.2011
comment
@ Аарон, у тебя более 50 вопросов без принятого ответа. Возможно, вы могли бы следить за ответами, чтобы они были приемлемыми.   -  person Peter Lawrey    schedule 29.07.2011
comment
Я понимаю что ты имеешь ввиду. Некоторые из моих вопросов, вероятно, слишком сложны для SO; существующие ответы неудовлетворительны (например, stackoverflow.com/questions /6136769/ или stackoverflow.com/questions/6135570/ циклический-буфер-со-считывателями).   -  person Aaron Digulla    schedule 29.07.2011


Ответы (4)


Вы можете изменить класс Runtime, чтобы журнал вызывал gc() в файл (System.gc() вызывает Runtime.gc())

Для этого отредактируйте копию, скомпилируйте ее и добавьте в свой -Xbootclasspath/p:

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

Можешь попробовать запустить

jstat -gccause {pid} 5s 
person Peter Lawrey    schedule 29.07.2011
comment
Однако, насколько я понимаю, вы не можете изменить класс Runtime, потому что gc() — это нативный метод. Вы можете изменить System.gc(), но это не единственное место, где можно вызвать Runtime.getRuntime().gc() — например, sun.management.MemoryImpl. Конечно, библиотека также может называть это так, поэтому журнал System может не рассказать вам все. - person doc; 26.05.2020

Некоторые библиотеки, которые вы используете, могут вызывать явный вызов gc. Вы можете отключить его с помощью -XX:-DisableExplicitGC и посмотреть, останавливается ли он Full GC в журналах.

person denis.solonenko    schedule 29.07.2011
comment
Хорошая точка зрения; таким образом, я могу быстро отличить явные вызовы сборщика мусора от вызовов нехватки памяти. - person Aaron Digulla; 29.07.2011

Используйте следующий скрипт скобок и jvisualvm с плагином btrace, чтобы легко выявить вызывающего абонента System.gc.

// import all BTrace annotations
import com.sun.btrace.annotations.*;

// import statics from BTraceUtils class
import static com.sun.btrace.BTraceUtils.*;

// @BTrace annotation tells that this is a BTrace program
@BTrace
public class GCcaller {
    // @OnMethod annotation tells where to probe.
    // In this example, we are interested in entry
    // into the Thread.start() method.
    @OnMethod(
        clazz="java.lang.System",
        method="gc"
    )
    public static void func() {
        // println is defined in BTraceUtils
        // you can only call the static methods of BTraceUtils
        println("about to start a System.gc!");
        jstack();
    }
}
person WENPIN    schedule 15.03.2016

В Java вы не можете «вызвать» сборщик мусора. Если вы видите документацию когда вы вызываете метод System.gc(), виртуальная машина просто принимает предложение запустить сборщик мусора, но нет гарантии, что он будет вызван эффективно. Это внутренний процесс, который будет вызываться автоматически, даже если вы не вызываете его, когда ему требуется место в стеке.

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

person jasalguero    schedule 29.07.2011
comment
+1 Хорошая мысль. В моем случае для анализа проблемы использовался инструмент, который показал, что 17 из 449 коллекций (3786%) были инициированы вызовами System.gc(). - person Aaron Digulla; 29.07.2011