Есть ли способ запустить агрессивную и полную сборку мусора в Java? - PullRequest
6 голосов
/ 06 апреля 2010

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

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

Есть ли способ вызвать его, чтобы быть уверенным, что он восстановится настолько, насколько это возможно, в условиях профилирования (это, конечно, не имеет смысла для производства)? Или «называть это несколько раз» - единственный способ быть «почти уверенным»?

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

Ответы [ 4 ]

4 голосов
/ 08 апреля 2010

Вообще говоря, «полная сборка мусора» не определена. GC обнаруживает недоступные объекты и восстанавливает их. Так получилось, что большинство реализаций 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() - это больше, чем «подсказка», и действительно вызывает некоторую активность GC. JVM от Sun может быть запущена с флагом «-XX: -DisableExplicitGC», который преобразует Runtime.gc() в бездействие, эффективно предотвращая выполнение кода, приведенного выше.

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

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

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

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

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

4 голосов
/ 06 апреля 2010

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

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

Очевидно, по чистым причинам тестирования:)

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

2 голосов
/ 06 апреля 2010

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

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

1 голос
/ 06 апреля 2010

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

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

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

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