Существует ли способ запустить агрессивную и полную сборку "мусора" в Java?

По причинам оптимизации памяти я запускаю меня сборщик "мусора" во время профилирования, чтобы проверить, убраны ли объекты правильно после избавления от них.

Вызов к сборщику "мусора" недостаточно, тем не менее, и кажется, что нет никакой гарантии того, что он уберет.

Существует ли способ назвать его, быть уверенным, что это восстановится так, как это может в профильных условиях (это не имело бы никакого смысла в производстве, конечно)? Или "называет несколько раз" единственным способом быть "почти уверенным"?

Или я просто неправильно понимал что-то о Сборщике "мусора"?

6
задан Gnoupi 6 April 2010 в 13:10
поделиться

4 ответа

Вообще говоря, «полная сборка мусора» некорректно определена. Сборщик мусора обнаруживает недоступные объекты и восстанавливает их. Так получилось, что большинство реализаций GC работают на «циклической» основе, и после того, как полный цикл завершится, можно определить правильное понятие «освобожденное пространство». Следовательно, если вы можете запустить полный цикл, и в этом цикле вообще не было обнаружено пригодного для использования пространства, а приложение в противном случае «простаивает» (например, не обновляет указатели), тогда вы можете сказать, что вы временно достигли точки «полностью собранного». .

Таким образом, вы можете сделать что-то вроде этого:

Runtime r = Runtime.getRuntime();
r.gc();
long f = r.freeMemory();
long m = r.maxMemory();
long t = r.totalMemory();
for (;;) {
    r.gc();
    long f2 = r.freeMemory();
    long m2 = r.maxMemory();
    long t2 = r.totalMemory();
    if (f == f2 && m == m2 && t == t2) 
        break;
    f = f2; 
    m = m2; 
    t = t2; 
}   
System.out.println("Full GC achieved.");

Этот код основан на некоторых предположениях, главным из которых является то, что Runtime.gc () больше, чем «подсказка», и на самом деле вызывает некоторую активность сборщика мусора. JVM Sun может быть запущена с флагом «-XX: -DisableExplicitGC», который преобразует Runtime.gc () в бездействующий, эффективно предотвращая выполнение каких-либо действий приведенным выше кодом.

Также есть несколько предостережений:

  • JVM может иметь некоторую фоновую непрерывную активность, например Таймер потоков. Некоторые из этих действий могут быть «скрытыми», т. Е. Не кодом, написанным разработчиком приложения. Также подумайте о потоке диспетчера событий AWT / Swing.

  • Запуск GC может вызвать дополнительную асинхронную активность через финализируемые объекты или мягкие / слабые / фантомные ссылки. Такая активность обязательно является асинхронной и может выполняться неограниченное количество времени. Время выполнения.gc () не будет ждать его завершения. На самом деле это вопрос определения: вы считаете сборщик мусора "завершенным", если финализаторы и очереди ссылок еще не обработаны?

  • На самом деле ничто не заставляет приведенный выше код завершаться ...

Для «более полного» сборщика мусора вы можете использовать интерфейс JVMTI (тот, который используется отладчиками), который позволяет запускать сборщик мусора, но также для приостановки целевых потоков JVM, что значительно усложняет задачу. легче определить и достичь состояния «полной сборки мусора».

4
ответ дан 9 December 2019 в 22:31
поделиться

Принудительно выделить максимальный объем доступной памяти. Когда JVM находится в углу OutOfMemoryError , она принудительно запускает сборщик мусора.

byte[] boom = new byte[512 * 1024 * 1024]; // Assuming 512MB

Очевидно, чисто из соображений тестирования :)

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

4
ответ дан 9 December 2019 в 22:31
поделиться

Нет, вы не можете детерминированно запустить полную сборку мусора.

Если то, что вам нужно, - это убедиться, что сборщик мусора вообще работает во время вашей попытки профилирования, чтобы удалить любые объекты, которые обычно удаляются (чтобы вы могли найти фактические утечки), тогда лучше всего чтобы убедиться, что ваши тестовые прогоны выполняются достаточно долго, когда вы можете разумно ожидать, что GC будет работать (или будет запускаться несколько раз).

2
ответ дан 9 December 2019 в 22:31
поделиться

По сути, все, что вы можете сделать, это следующее:

Runtime r = Runtime.getRuntime();
r.gc();

Однако имейте в виду, что все ссылки, к которым можно каким-то образом добраться, считаются живыми, даже если вы думаете, что это не так. В зависимости от конкретного GC и настроек он может собирать или не собирать (большую часть) памяти, которая не является "живой".

1
ответ дан 9 December 2019 в 22:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: