Когда System.gc () что-то делает?

118

Я знаю, что сборка мусора в Java автоматизирована. Но я понял, что если вы вызовете System.gc()свой код, JVM может решить или не решить выполнить сборку мусора в этот момент. Как именно это работает? На каком основании / параметрах именно JVM решает делать (или не делать) сборщик мусора, когда видит System.gc()?

Есть ли какие-нибудь примеры, и в таком случае было бы неплохо поместить это в свой код?

Майкл
источник
4
Слишком сложная концепция для полной детализации здесь, но эта статья должна вам помочь: chaoticjava.com/posts/how-does-garbage-collection-work
GEOCHET
Точное поведение зависит от JVM, т.е. зависит от реализации.
Thorbjørn Ravn Andersen

Ответы:

59

На практике обычно решает сделать сборку мусора. Ответ зависит от множества факторов, например от того, на какой JVM вы работаете, в каком режиме она работает и какой алгоритм сборки мусора использует.

Я бы не стал полагаться на это в вашем коде. Если JVM собирается выбросить OutOfMemoryError, вызов System.gc () не остановит его, потому что сборщик мусора попытается освободить столько, сколько сможет, прежде чем он дойдет до этой крайности. Единственный раз, когда я видел его на практике, - это в IDE, где он прикреплен к кнопке, которую пользователь может нажать, но даже там это не очень полезно.

jodonnell
источник
3
вы можете принудительно
выполнить
25
@bene Вы действительно можете "заставить" это? Jconsole просто вызывает System.gc ()?
Джон Мигер
4
Я бы использовал System.gc()на экране загрузки видеоигры. В тот момент мне было бы все равно, очистил ли вызов все, что он мог, или вообще ничего не сделал. Однако я бы предпочел, чтобы он «тратил усилия на переработку неиспользуемых объектов» во время экрана загрузки, а не во время игры.
Kröw
30

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

Гильермо Васконселос
источник
4
Да, я тоже этим занимаюсь. Значения, возвращаемые Runtime.freeMemory (), например, действительно значимы только после System.gc (), потому что обычно вы хотите знать, сколько памяти заблокировано несобираемыми экземплярами. Только для использования при отладке / профилировании памяти, конечно, но никогда в производстве.
sleske
Нет, это хорошо и для многих других сценариев. Например, допустим, у вас есть один шаблон, учитывающий жизненный цикл. В onStop (), если вы обнуляете экземпляр, рекомендуется вызвать System.gc (), чтобы помочь ему.
портфолио
26

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

Теперь, если вы посмотрите исходный код OpenJDK , который является основой Oracle JVM, вы увидите, что вызов System.gc()действительно запускает цикл GC. Если вы используете другую JVM, такую ​​как J9, вам нужно проверить их документацию, чтобы узнать ответ. Например, JVM Azul имеет сборщик мусора, который работает постоянно, поэтому вызов System.gc()ничего не сделает.

В другом ответе упоминается запуск GC в JConsole или VisualVM. По сути, эти инструменты делают удаленный вызов System.gc().

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

Однако есть несколько случаев, когда призыв System.gc()может быть понятным. Рассмотрим, например, микротест. Никто не хочет, чтобы цикл GC происходил в середине микробенчмарка. Таким образом, вы можете запускать цикл ГХ между каждым измерением, чтобы каждое измерение начиналось с пустой кучи.

Пьер Ляпорт
источник
26

У вас нет контроля над сборщиком мусора в java - решает виртуальная машина. Я ни разу не встречал случая, когда System.gc()это необходимо . Поскольку System.gc()вызов просто ПРЕДЛАГАЕТ, что виртуальная машина выполняет сборку мусора, а также выполняет ПОЛНУЮ сборку мусора (старые и новые поколения в куче нескольких поколений), он может фактически вызвать БОЛЬШЕ циклов процессора, чем необходимо.

В некоторых случаях может иметь смысл предложить виртуальной машине выполнить полную сборку СЕЙЧАС, поскольку вы можете знать, что приложение будет бездействовать в течение следующих нескольких минут, прежде чем произойдет тяжелая работа. Например, сразу после инициализации большого количества временных объектов во время запуска приложения (т. Е. Я только что кэшировал ТОННУ информации и знаю, что в течение минуты или около того у меня не будет большой активности). Подумайте о запуске IDE, например о запуске eclipse - он многое делает для инициализации, поэтому, возможно, сразу после инициализации имеет смысл выполнить полный gc на этом этапе.

DustinB
источник
17

При звонке нужно быть очень осторожным System.gc(). Его вызов может добавить ненужные проблемы с производительностью в ваше приложение, и не гарантируется фактическое выполнение сбора. Фактически можно отключить явное System.gc()использование аргумента java -XX:+DisableExplicitGC.

Я настоятельно рекомендую прочитать документы, доступные на Java HotSpot Garbage Collection, чтобы получить более подробные сведения о сборке мусора.

Дэвид Шлоснагл
источник
Мое приложение для Android всегда выдает исключение OutOfMemoryException. Итак, я подумал об использовании System.gc () в функции onDestroy моего класса, чтобы очистить все нежелательные ссылки и объекты. Это хороший подход
Сагар Деванга
2
@Sagar Devanga Ручной вызов gc, как вы описываете, вряд ли поможет. Перед запуском OOM JVM уже попытается выполнить сборку мусора, чтобы освободить память
Scrubbie
10

System.gc()реализуется виртуальной машиной, и то, что она делает, зависит от реализации. Разработчик может, например, просто вернуться и ничего не делать.

Что касается того, когда запускать сбор вручную, единственный раз, когда вы можете захотеть это сделать, - это когда вы отказываетесь от большой коллекции, содержащей множество меньших коллекций - Map<String,<LinkedList>> например, - и вы хотите попробовать и тогда выполнить хит, и есть, но по большей части вам не стоит об этом беспокоиться. К сожалению, GC знает лучше вас большую часть времени.

Патрик
источник
8

Если вы используете прямые буферы памяти, JVM не запускает GC за вас, даже если у вас мало прямой памяти.

Если вы звоните ByteBuffer.allocateDirect()и получаете OutOfMemoryError, вы можете обнаружить, что этот вызов в порядке после запуска GC вручную.

Питер Лоури
источник
Вы говорите, что System.gc () собирает прямые распределения, тогда как JVM обычно этого не делает (до того, как бросить OOM). Потому что я считаю, что это неправильно. Единственная причина, по которой распределение может быть успешным после явного GC, - это дополнительное время и некоторая большая вероятность освобождения объекта в куче с финализатором (и освобождения некоторого непосредственно выделенного объекта).
eckes
В последней версии Java 6 код в allocateBuffer всегда будет запускать System.gc () перед выдачей OutOfMemoryError. В коде завершения он имеет сокращение, для Cleanersкоторого используется прямая память. то есть он не освобождается потоком финализатора, так как это может быть слишком медленным. Тем не менее, можно получить OOME, если вы особенно быстро создаете области прямой памяти. Решение состоит в том, чтобы не делать этого и повторно использовать области прямой памяти там, где это возможно.
Питер Лоури
1
спасибо, это больше похоже на мой опыт. Думаю, ответ верен только для старых версий Java.
eckes
5

Большинство JVM запускают сборщик мусора (в зависимости от переключателей -XX: DiableExplicitGC и -XX: + ExplicitGCInvokesConcurrent). Но спецификация просто менее четко определена, чтобы позволить более эффективную реализацию позже.

Спецификация нуждается в пояснении: Ошибка № 6668279: (spec) System.gc () должна указывать на то, что мы не рекомендуем использовать и не гарантируем поведение

Внутренне метод gc используется RMI и NIO, и они требуют синхронного выполнения, что: в настоящее время обсуждается:

Ошибка № 5025281: Разрешить System.gc () запускать одновременные (не останавливающие мир) полные коллекции

Экес
источник
3

Garbage Collectionхорошо Java, если мы выполняем программное обеспечение, закодированное на java, на рабочем столе / ноутбуке / сервере. Вы можете позвонить System.gc()или Runtime.getRuntime().gc()войти Java.

Просто обратите внимание, что ни один из этих вызовов не даст никаких гарантий. Это просто предложение для jvm запустить сборщик мусора. Это зависит от JVM, независимо от того, запускает ли она GC или нет. Итак, короткий ответ: мы не знаем, когда он запустится. Более длинный ответ: JVM запустит gc, если для этого будет время.

Думаю, то же самое и с Android. Однако это может замедлить работу вашей системы.

Нэвин
источник
JVM будет запускать gc, если для этого есть время : не всегда верно, Jvm может запускать gc, когда память Eden заполнена.
abdelmouheimen
2

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

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

Когда вы сопоставляете файл с памятью, я считаю, что вызов map () вызывает исключение IOException, когда достаточно большой блок памяти недоступен. Я думаю, что сборка мусора непосредственно перед файлом map () может помочь предотвратить это. Что вы думаете?


источник
2

мы никогда не сможем заставить сборку мусора. System.gc предлагает только vm для сборки мусора, однако на самом деле, в какое время механизм запускается, никто не знает, это как указано в спецификациях JSR.

lwpro2
источник
2

Следует ОЧЕНЬ много сказать о том, чтобы потратить время на проверку различных настроек сборки мусора, но, как было упомянуто выше, обычно это бесполезно.

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

Следовательно, единственное время, когда мое приложение вызывает System.gc (), - это когда оно собирается войти в сегмент кода, где будут выделены большие буферы, необходимые для обработки данных, и проверка доступной свободной памяти показывает, что я не гарантированно иметь это. В частности, я смотрю на среду размером 1 ГБ, где не менее 300 МБ занято статическими данными, при этом основная часть нестатических данных связана с выполнением, за исключением случаев, когда обрабатываемые данные составляют не менее 100-200 МБ при источник. Все это часть процесса автоматического преобразования данных, поэтому все данные существуют в течение относительно коротких периодов времени в долгосрочной перспективе.

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

При этом, несмотря на то, что я использую System.gc (), я продолжал настраивать параметры командной строки и смог значительно улучшить общее время обработки моего приложения, несмотря на то, что не смог преодолеть Камень преткновения возникает при работе с большими блоками данных. При этом System.gc () - это инструмент ... очень ненадежный инструмент, и если вы не будете осторожны с тем, как вы его используете, вы захотите, чтобы он не работал чаще, чем нет.

Kyune
источник
2

Если вы хотите знать, System.gc()вызывается ли ваш , вы можете с новым обновлением Java 7 4 получать уведомление, когда JVM выполняет сборку мусора.

Я не на 100% уверен, что класс GarbageCollectorMXBean был представлен в Java 7 update 4, хотя я не мог найти его в примечаниях к выпуску, но я нашел информацию на сайте javaperformancetuning .com

Шервин Асгари
источник
0

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

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

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

zxcv
источник
2
Мы вызываем System.gc (), чтобы попытаться закрыть наши объекты MappedByteBuffer, которые в противном случае не были бы закрыты и, следовательно, недоступны для других процессов или для усечения файлов, даже если мы вызываем close () для объектов. К сожалению, это не всегда закрывает их.
Тим Купер
0

Согласно «Мышлению на Java» Брюса Экеля, один из вариантов использования явного вызова System.gc () - это когда вы хотите принудительно завершить завершение, то есть вызов метода финализации .

звездочка
источник
NB: существует собственный метод принудительного запуска финализации. (Проблема на самом деле не в запуске финализаторов, а в признании того, что объект может быть завершен, потому что на него нет
ссылок
-1

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

fleture
источник