После ответа на вопрос о том, как принудительно освобождать объекты в Java (парень очищал HashMap 1,5 ГБ) System.gc()
, мне сказали, что это плохая практика - вызывать System.gc()
вручную, но комментарии не были полностью убедительными. Кроме того, никто, казалось, не осмеливался ни отрицать, ни отрицать мой ответ.
Там мне сказали, что это плохая практика, но потом мне также сказали, что работы сборщика мусора систематически не останавливают мир, и что он также может эффективно использоваться JVM только в качестве подсказки, так что я вроде как в убыток.
Я понимаю, что JVM обычно лучше вас знает, когда ему нужно восстановить память. Я также понимаю, что беспокоиться о нескольких килобайтах данных глупо. Я также понимаю, что даже мегабайты данных - это не то, что было несколько лет назад. Но все же 1,5 гигабайта? И вы знаете, что в памяти висит около 1,5 ГБ данных; это не похоже на выстрел в темноте. Это System.gc()
систематически плохо или есть какой-то момент, когда все становится хорошо?
Так что вопрос на самом деле двойной:
- Почему звонить или не плохая практика
System.gc()
? Действительно ли это просто подсказка JVM при определенных реализациях, или это всегда полный цикл сбора? Есть ли на самом деле реализации сборщика мусора, которые могут выполнять свою работу, не останавливая мир? Пожалуйста, пролите некоторый свет на различные утверждения, сделанные людьми в комментариях к моему ответу . - Где порог? Это никогда не хорошая идея, чтобы позвонить
System.gc()
, или есть моменты, когда это приемлемо? Если так, то что это за времена?
источник
Ответы:
Причина, по которой все всегда говорят избегать,
System.gc()
заключается в том, что это довольно хороший показатель принципиально неработающего кода . Любой код, который зависит от него на правильность, безусловно, нарушен; все, что зависит от производительности, скорее всего, сломаны.Вы не знаете, под каким сборщиком мусора вы работаете. Конечно, есть такие, которые не «останавливают мир», как вы утверждаете, но некоторые JVM не настолько умны или по разным причинам (возможно, они разговаривают по телефону?) Не делают этого. Вы не знаете, что он собирается делать.
Кроме того, ничего не гарантировано. JVM может просто полностью игнорировать ваш запрос.
Сочетание «вы не знаете, что это будет делать», «вы не знаете, поможет ли это вообще» и «вам не нужно так или иначе называть это», - вот почему люди так решительно говорят, что в целом ты не должен называть это Я думаю, что это случай "если вам нужно спросить, следует ли вам использовать это, вы не должны"
РЕДАКТИРОВАТЬ, чтобы устранить некоторые проблемы из другого потока:
Прочитав ветку, на которую вы ссылались, я хотел бы отметить еще несколько вещей. Во-первых, кто-то предположил, что вызов
gc()
может вернуть память системе. Это, конечно, не обязательно верно - сама куча Java растет независимо от распределения Java.Как и в случае, JVM будет держать память (много десятков мегабайт) и увеличивать кучу по мере необходимости. Он не обязательно возвращает эту память системе, даже когда вы освобождаете объекты Java; он совершенно свободен для хранения выделенной памяти, чтобы использовать ее для будущих распределений Java.
Чтобы показать, что возможно, что
System.gc()
ничего не делает, просмотрите:http://bugs.sun.com/view_bug.do?bug_id=6668279
и, в частности, есть опция -XX: DisableExplicitGC VM.
источник
System.gc()
это полезно и даже может быть необходимо. Например, в приложениях с пользовательским интерфейсом в Windows он может значительно ускорить процесс восстановления окна, когда вы вызываете System.gc (), прежде чем свернуть окно (особенно, когда оно остается свернутым в течение достаточно долгого времени, а часть процесса переключается на диск).WeakReference
s для объектов, к которым вы хотите привязаться, неверен с самого начала, сборщик мусора или нет. У вас возникнет та же проблема с C ++std::weak_ptr
(хотя вы можете заметить проблему в версии C ++ раньше, чем в версии Java, поскольку уничтожение объектов не будет отложено, как это обычно происходит с финализацией).System.gc()
исправляет это, является обходным путем, не хорошей практикой кодирования.Уже было объяснено, что вызов
system.gc()
может ничего не делать, и что любой код, которому «нужен» сборщик мусора для запуска, не работает.Однако прагматическая причина, по которой называть это плохой практикой,
System.gc()
заключается в том, что она неэффективна. И в худшем случае это ужасно неэффективно ! Позволь мне объяснить.Типичный алгоритм GC идентифицирует мусор путем обхода всех объектов без мусора в куче и выведения, что любой объект, который не был посещен, должен быть мусором. Исходя из этого, мы можем смоделировать общую работу сборки мусора, состоящую из одной части, которая пропорциональна количеству активных данных, и другой части, которая пропорциональна количеству мусора; то есть
work = (live * W1 + garbage * W2)
.Теперь предположим, что вы делаете следующее в однопоточном приложении.
Первый вызов (мы предсказываем)
(live * W1 + garbage * W2)
сработает и избавится от нерешенного мусора.Второй звонок сделает
(live* W1 + 0 * W2)
работу и ничего не исправит. Другими словами, мы сделали(live * W1)
работу и ничего не добились .Мы можем смоделировать эффективность коллектора как объем работы, необходимой для сбора единицы мусора; то есть
efficiency = (live * W1 + garbage * W2) / garbage
. Таким образом, чтобы сделать GC настолько эффективным, насколько это возможно, нам нужно максимально увеличить значение,garbage
когда мы запускаем GC; т.е. ждать, пока куча не заполнится. (А также, сделайте кучу как можно больше. Но это отдельная тема.)Если приложение не вмешивается (вызывая
System.gc()
), GC будет ждать, пока куча не заполнится, прежде чем запускаться, что приведет к эффективному сбору мусора 1 . Но если приложение заставляет GC работать, есть вероятность, что куча не будет заполнена, и в результате мусор будет собираться неэффективно. И чем чаще приложение заставляет GC, тем более неэффективным становится GC.Примечание: приведенное выше объяснение скрывает тот факт, что типичный современный GC разделяет кучу на «пробелы», GC может динамически расширять кучу, рабочий набор приложения, не содержащий мусора, может меняться и так далее. Тем не менее, один и тот же базовый принцип применим ко всем истинным сборщикам мусора 2 . Неэффективно заставить GC работать.
1 - так работает коллектор "пропускная способность" Параллельные сборщики, такие как CMS и G1, используют разные критерии, чтобы решить, когда запускать сборщик мусора.
2 - Я также исключаю менеджеры памяти, которые используют исключительно подсчет ссылок, но ни одна из современных реализаций Java не использует этот подход ... по уважительной причине.
источник
Кажется, многие люди говорят тебе не делать этого. Я не согласен. Если после большого процесса загрузки, такого как загрузка уровня, вы считаете, что:
вызов System.gc () не причинит вреда. Я смотрю на это как
inline
ключевое слово c / c ++ . Это просто намек на то, что вы, разработчик, решили, что время / производительность не так важны, как обычно, и что некоторые из них могут быть использованы для восстановления памяти.Совет не полагаться на то, что он делает что-либо, является правильным. Не надейтесь, что это сработает, но намек на то, что сейчас подходящее время для сбора, вполне подойдет. Я бы предпочел тратить время в той части кода, где это не имеет значения (экран загрузки), чем когда пользователь активно взаимодействует с программой (например, на уровне игры).
Есть один случай, когда я буду принудительно собирать данные: при попытке выяснить, происходит ли утечка определенного объекта (или нативный код, или большое, сложное взаимодействие с обратным вызовом. О, и любой компонент пользовательского интерфейса, который смотрит на Matlab.) Это никогда не должно использоваться. в производственном коде.
источник
stop the world
подхода, и это реальный вред, если это произойдетЛюди хорошо поработали, объяснив, почему НЕ использовать, поэтому я расскажу вам пару ситуаций, где вы должны его использовать:
(Следующие комментарии относятся к Hotspot, работающему в Linux с коллектором CMS, где я уверен, говоря, что
System.gc()
на самом деле он всегда вызывает полную сборку мусора).После начальной работы по запуску приложения у вас может быть ужасное состояние использования памяти. Половина вашего заемного поколения может быть полна мусора, а это значит, что вы намного ближе к своей первой CMS. В приложениях, где это имеет значение, неплохо было бы вызывать System.gc () для «сброса» вашей кучи в исходное состояние живых данных.
В том же ключе, что и в # 1, если вы внимательно следите за использованием кучи, вы хотите иметь точное представление о том, каково ваше базовое использование памяти. Если первые 2 минуты времени безотказной работы вашего приложения полностью инициализируются, ваши данные будут испорчены, если вы не заставите (хм ... «предложить») полный сбор данных.
У вас может быть приложение, которое разработано так, чтобы никогда не рекламировать что-либо для постоянного поколения, пока оно работает. Но, возможно, вам нужно заранее инициализировать некоторые данные, которые не настолько велики, чтобы автоматически переходить к постоянному поколению. Если вы не вызовете System.gc () после того, как все настроено, ваши данные могут находиться в новом поколении, пока не придет время для их продвижения. Внезапно ваше сверхпопулярное приложение с малой задержкой и низким ГХ получает огромный (условно говоря) штраф за задержку за продвижение этих объектов во время обычных операций.
Иногда полезно иметь доступ к System.gc в производственном приложении для проверки наличия утечки памяти. Если вы знаете, что набор активных данных в момент времени X должен существовать в определенном соотношении с набором активных данных в момент времени Y, то было бы полезно вызвать System.gc () для времени X и времени Y и сравнить использование памяти. ,
источник
System.gc()
один раз вызов для принудительного продвижения объектов ничего не даст. И вы, конечно, не хотите звонитьSystem.gc()
восемь раз подряд и молиться о том, чтобы сейчас продвижение было выполнено, а сэкономленные затраты на последующее продвижение оправдывают затраты на несколько полных сборов мусора. В зависимости от алгоритма GC, продвижение большого количества объектов может даже не иметь фактических затрат, так как будет просто переназначать память старому поколению или копировать одновременно ...Это очень утомительный вопрос, и я чувствую, что многие выступают против Java, несмотря на то, насколько он полезен для языка.
Тот факт, что вы не можете доверять «System.gc» делать что-либо, невероятно пугающий и может легко вызвать чувство «страха, неуверенности, сомнения» в языке.
Во многих случаях полезно иметь дело с скачками памяти, которые вы намеренно вызываете до того, как произойдет важное событие, которое заставит пользователей думать, что ваша программа плохо спроектирована / не отвечает.
Возможность контролировать сборку мусора была бы очень хорошим образовательным инструментом, в свою очередь, улучшая понимание людьми того, как сборка мусора работает и как программы используют ее поведение по умолчанию, а также контролируемое поведение.
Позвольте мне рассмотреть аргументы этой темы.
Часто программа может ничего не делать, и вы знаете, что она ничего не делает из-за того, как она была задумана. Например, он может выполнять какое-то долгое ожидание с большим окном сообщения ожидания, и в конце он может также добавить вызов для сбора мусора, потому что время его запуска займет действительно небольшую долю времени долгое ожидание, но gc не будет действовать в середине более важной операции.
Я не согласен, не имеет значения, какой у вас сборщик мусора. Его работа состоит в том, чтобы отслеживать мусор и убирать его.
Вызывая gc во время, когда использование менее критично, вы уменьшаете шансы его запуска, когда ваша жизнь зависит от того, какой код выполняется, но вместо этого он решает собирать мусор.
Конечно, он может вести себя не так, как вы хотите или ожидаете, но когда вы действительно хотите позвонить, вы знаете, что ничего не происходит, и пользователь готов терпеть медлительность / время простоя. Если System.gc работает, отлично! Если это не так, по крайней мере, вы пытались. Там просто нет недостатка, если сборщик мусора не имеет внутренних побочных эффектов, которые делают что-то ужасно неожиданное для поведения сборщика мусора, если он вызывается вручную, и это само по себе вызывает недоверие.
Это вариант использования, который не может быть достигнут надежно, но может быть, если система была разработана таким образом. Это все равно, что сделать светофор и сделать так, чтобы некоторые / все кнопки светофора ничего не делали, это заставляет вас задаться вопросом, почему кнопка существует для начала, в javascript нет функции сбора мусора, поэтому мы Тщательно изучите это.
что такое "подсказка"? что такое "игнорировать"? компьютер не может просто получать подсказки или игнорировать что-то, существуют строгие поведенческие пути, которые могут быть динамическими и руководствуются намерениями системы. Правильный ответ будет включать то, что фактически делает сборщик мусора на уровне реализации, что заставляет его не выполнять сбор, когда вы запрашиваете его. Эта функция просто нет? Есть ли какие-то условия, которые я должен выполнить? Каковы эти условия?
В настоящее время Java GC часто кажется монстром, которому вы просто не доверяете. Вы не знаете, когда он придет или уйдет, вы не знаете, что он собирается делать, как он собирается это делать. Я могу себе представить, что некоторые эксперты лучше понимают, как их сборщик мусора работает на основе каждой инструкции, но подавляющее большинство просто надеется, что это «просто работает», и необходимость доверять непрозрачному алгоритму, выполняющему для вас работу, разочаровывает.
Существует большой разрыв между чтением чего-либо или обучением чему-либо, и фактическим наблюдением за реализацией этого, различиями между системами и возможностью играть с этим без необходимости смотреть на исходный код. Это создает уверенность и чувство мастерства / понимания / контроля.
Подводя итог, можно сказать, что в ответах есть одна проблема: эта функция может ничего не делать, и я не буду вдаваться в подробности, как определить, когда она что-то делает, а когда нет, и почему она не будет или не будет, часто намекает на то, что попытка сделать это просто против философии, даже если намерения, стоящие за ней, разумны ».
Для Java GC может быть нормально вести себя так, как оно есть, а может и нет, но, чтобы понять это, трудно действительно понять, в каком направлении идти, чтобы получить исчерпывающий обзор того, что вы можете доверять GC и не делать, так что слишком просто просто не доверять языку, потому что цель языка - контролировать поведение до философского уровня (программисту, особенно новичкам, легко впасть в экзистенциальный кризис от определенных поведений системы / языка) способны терпеть (и если вы не можете, вы просто не будете использовать язык, пока вам не придется), и больше вещей, которые вы не можете контролировать без какой-либо известной причины, почему вы не можете контролировать их, по своей сути вредны.
источник
Эффективность GC зависит от ряда эвристик. Например, распространенная эвристика заключается в том, что доступ на запись к объектам обычно происходит на объектах, которые были созданы не так давно. Другой заключается в том, что многие объекты очень недолговечны (некоторые объекты будут использоваться в течение длительного времени, но многие будут отброшены через несколько микросекунд после их создания).
Звонить
System.gc()
- это все равно что пинать ГК. Это означает: «все эти тщательно настроенные параметры, эти умные организации, все усилия, которые вы просто вкладываете в распределение и управление объектами таким образом, чтобы все прошло гладко, ну, просто отбросьте всю партию и начинайте с нуля». Это может улучшить производительность, но в большинстве случаев это просто снижает производительность.Для
System.gc()
надежного использования (*) вам необходимо знать, как работает ГХ, во всех его мелких деталях. Такие детали могут немного измениться, если вы используете JVM от другого поставщика, или следующую версию от того же поставщика, или ту же JVM, но с немного другими параметрами командной строки. Так что это редко хорошая идея, если только вы не хотите решить конкретную проблему, в которой вы контролируете все эти параметры. Отсюда и понятие «плохой практики»: это не запрещено, метод существует, но он редко окупается.(*) Я говорю об эффективности здесь.
System.gc()
никогда не сломает правильную программу на Java. Он также не вызовет дополнительной памяти, которую JVM не могла бы получить иначе: перед броскомOutOfMemoryError
JVM выполняет свою работуSystem.gc()
, даже если в качестве последнего средства.источник
Иногда ( не часто! ) Вы действительно знаете больше о прошлом, текущем и будущем использовании памяти, чем время выполнения. Это случается не очень часто, и я бы никогда не заявил, что в веб-приложении это происходит, пока обслуживаются обычные страницы.
Много лет назад я работаю над генератором отчетов,
Во-первых, поскольку это было не в реальном времени, и пользователи ожидали ожидания отчета, задержка во время выполнения GC не была проблемой, но нам нужно было создавать отчеты со скоростью, которая была быстрее, чем они запрашивались.
Глядя на вышеприведенный план процесса, становится ясно, что.
Таким образом, очевидно, что выполнение GC стоит, когда очередь запросов пуста; в этом не было недостатка.
Возможно, стоит выполнить прогон GC после отправки каждого отчета по электронной почте, так как мы знаем, что это подходящее время для прогона GC. Однако если бы на компьютере было достаточно оперативной памяти, лучшие результаты были бы получены при задержке запуска GC.
Это поведение было настроено для каждой установки, для некоторых клиентов включение принудительного GC после каждого отчета значительно ускоряло защиту отчетов. (Я ожидаю, что это произошло из-за нехватки памяти на их сервере, и на нем запущено множество других процессов, поэтому отсюда время, затрачиваемое GC на пейджинг, сократилось)
Мы никогда не обнаруживали установку, которая не приносила пользы - принудительный запуск GC каждый раз, когда рабочая очередь была пуста.
Но, давайте проясним, что вышеупомянутое не является частым случаем.
источник
Может быть, я пишу дрянной код, но я понял, что щелкнуть значок корзины в IDE Eclipse и NetBeans - это «хорошая практика».
источник
System.gc()
периодический вызов , вы, вероятно, найдете поведение раздражающим.Во-первых, есть разница между спецификацией и реальностью. В спецификации сказано, что System.gc () является подсказкой, что GC должен работать, а виртуальная машина может игнорировать это. Реальность такова, что виртуальная машина никогда не будет игнорировать вызов System.gc ().
Вызов GC идет с нетривиальными накладными расходами на вызов, и если вы сделаете это в какой-то случайный момент времени, скорее всего, вы не увидите вознаграждения за ваши усилия. С другой стороны, естественно вызванная коллекция, вероятно, окупит затраты на вызов. Если у вас есть информация, указывающая на необходимость запуска GC, вы можете позвонить в System.gc () и увидеть преимущества. Однако, по моему опыту, это происходит только в нескольких крайних случаях, так как очень маловероятно, что у вас будет достаточно информации, чтобы понять, когда и когда следует вызывать System.gc ().
Один пример, приведенный здесь, попал в мусорную корзину в вашей IDE. Если вы отправляетесь на встречу, почему бы не ударить ее. Накладные расходы не повлияют на вас, и куча может быть очищена, когда вы вернетесь. Сделайте это в производственной системе, и частые звонки на сбор приведут к полной остановке! Даже случайные вызовы, например, сделанные RMI, могут негативно сказаться на производительности.
источник
Да, вызов System.gc () не гарантирует его выполнения, это запрос к JVM, который может быть проигнорирован. Из документов:
Это почти всегда плохая идея называть это, потому что автоматическое управление памятью, как правило, знает лучше, чем вы, когда gc. Это будет происходить при низком внутреннем пуле свободной памяти или при запросе операционной системы некоторой памяти.
Возможно, будет приемлемо вызвать System.gc (), если вы знаете, что это помогает. Под этим я подразумеваю, что вы тщательно протестировали и измерили поведение обоих сценариев на платформе развертывания , и вы можете показать, что это помогает. Имейте в виду, что gc не так легко предсказать - он может помочь при одном запуске и навредить при другом.
источник
По моему опыту, использование System.gc () фактически является платформной формой оптимизации (где «платформа» - это сочетание аппаратной архитектуры, ОС, версии JVM и возможных дополнительных параметров времени выполнения, таких как доступная оперативная память), поскольку его поведение, в то время как приблизительно предсказуемо для конкретной платформы, может (и будет) значительно различаться между платформами.
Да, там есть ситуации , в которых System.gc () улучшит (воспринимаемое) производительность. Например, если в некоторых частях вашего приложения допустимы задержки, а в других - нет (в приведенном выше примере игры вы хотите, чтобы сбор данных происходил в начале уровня, а не на уровне).
Однако то, поможет ли это или повредит (или ничего не сделает), сильно зависит от платформы (как определено выше).
Поэтому я думаю, что это действительно как последняя оптимизация для платформы (т. Е. Если других оптимизаций производительности недостаточно). Но вам никогда не следует называть это только потому, что вы считаете, что это может помочь (без конкретных ориентиров), потому что скорее всего, это не поможет.
источник
Поскольку объекты динамически распределяются с помощью оператора new,
вам может быть интересно, как такие объекты уничтожаются и их
память освобождается для последующего перераспределения.
В некоторых языках, таких как C ++, динамически размещаемые объекты должны быть освобождены вручную с помощью оператора удаления.
источник