Когда System.gc () что-то делает? - PullRequest
108 голосов
/ 16 сентября 2008

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

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

Ответы [ 17 ]

56 голосов
/ 16 сентября 2008

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

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

28 голосов
/ 16 сентября 2008

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

24 голосов
/ 16 сентября 2008

У вас нет контроля над GC в Java - решает виртуальная машина. Я никогда не сталкивался со случаем, когда System.gc() является необходимым . Поскольку System.gc() вызывает просто ПРЕДЛОЖЕНИЕ, что ВМ выполняет сборку мусора, а также ПОЛНУЮ сборку мусора (старое и новое поколения в куче из нескольких поколений), то это может фактически вызвать циклы MORE процессора быть потребленным, чем необходимо.

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

22 голосов
/ 11 мая 2013

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

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

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

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

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

17 голосов
/ 16 сентября 2008

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

Я бы настоятельно рекомендовал прочитать документы, доступные на Сборка мусора Java HotSpot для более подробной информации о сборке мусора.

10 голосов
/ 16 сентября 2008

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

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

8 голосов
/ 10 февраля 2009

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

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

4 голосов
/ 16 сентября 2008

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

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

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

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

2 голосов
/ 27 апреля 2013

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

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

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

2 голосов
/ 07 марта 2011

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

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

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

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

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

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