Почему плохой практикой является вызов System.gc ()?


326

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

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

Я понимаю, что JVM обычно лучше вас знает, когда ему нужно восстановить память. Я также понимаю, что беспокоиться о нескольких килобайтах данных глупо. Я также понимаю, что даже мегабайты данных - это не то, что было несколько лет назад. Но все же 1,5 гигабайта? И вы знаете, что в памяти висит около 1,5 ГБ данных; это не похоже на выстрел в темноте. Это System.gc()систематически плохо или есть какой-то момент, когда все становится хорошо?

Так что вопрос на самом деле двойной:

  • Почему звонить или не плохая практика System.gc()? Действительно ли это просто подсказка JVM при определенных реализациях, или это всегда полный цикл сбора? Есть ли на самом деле реализации сборщика мусора, которые могут выполнять свою работу, не останавливая мир? Пожалуйста, пролите некоторый свет на различные утверждения, сделанные людьми в комментариях к моему ответу .
  • Где порог? Это никогда не хорошая идея, чтобы позвонить System.gc(), или есть моменты, когда это приемлемо? Если так, то что это за времена?

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

41
Божо: обратите внимание на первое слово вопроса. Почему лучше не называть это? Простое повторение мантры не объясняет проклятую вещь.
Просто мое правильное мнение

1
Другой случай был объяснен в java-monitor.com/forum/showthread.php?t=188, где объясняется, как может быть плохой практикой вызывать System.gc ()
Ширишкумар Бари

Ответы:


243

Причина, по которой все всегда говорят избегать, 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.


1
Возможно, вам удастся создать какую-то странную установку Rube Goldberg-esque, в которой метод, в котором запускается GC, влияет на правильность вашего кода. Возможно, это маскирует какое-то странное взаимодействие с потоками, или, возможно, финализатор оказывает существенное влияние на работу программы. Я не совсем уверен, что это возможно, но возможно, поэтому я решил упомянуть об этом.
Стивен Шланскер

2
@zneak, например, вы могли бы поместить критический код в финализаторы (что в корне не работает)
Мартин,

3
Я хотел бы добавить, что есть несколько угловых случаев, когда System.gc()это полезно и даже может быть необходимо. Например, в приложениях с пользовательским интерфейсом в Windows он может значительно ускорить процесс восстановления окна, когда вы вызываете System.gc (), прежде чем свернуть окно (особенно, когда оно остается свернутым в течение достаточно долгого времени, а часть процесса переключается на диск).
Иоахим Зауэр

2
@AndrewJanke Я бы сказал, что код, который использует WeakReferences для объектов, к которым вы хотите привязаться, неверен с самого начала, сборщик мусора или нет. У вас возникнет та же проблема с C ++ std::weak_ptr(хотя вы можете заметить проблему в версии C ++ раньше, чем в версии Java, поскольку уничтожение объектов не будет отложено, как это обычно происходит с финализацией).
JAB

2
@rebeccah Это ошибка, так что да, я бы назвал ее «безусловно сломанной». Факт, который System.gc()исправляет это, является обходным путем, не хорошей практикой кодирования.
Стивен Шланскер

149

Уже было объяснено, что вызов system.gc() может ничего не делать, и что любой код, которому «нужен» сборщик мусора для запуска, не работает.

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

Типичный алгоритм GC идентифицирует мусор путем обхода всех объектов без мусора в куче и выведения, что любой объект, который не был посещен, должен быть мусором. Исходя из этого, мы можем смоделировать общую работу сборки мусора, состоящую из одной части, которая пропорциональна количеству активных данных, и другой части, которая пропорциональна количеству мусора; то есть work = (live * W1 + garbage * W2).

Теперь предположим, что вы делаете следующее в однопоточном приложении.

System.gc(); System.gc();

Первый вызов (мы предсказываем) (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 не использует этот подход ... по уважительной причине.


45
+1 Хорошее объяснение. Однако обратите внимание, что это рассуждение применимо только в том случае, если вы заботитесь о пропускной способности Если вы хотите оптимизировать латентность в определенных точках, форсирование GC может иметь смысл. Например, (гипотетически говоря) в игре вы можете избежать задержек во время уровней, но вас не волнуют задержки во время загрузки уровней. Тогда имеет смысл форсировать GC после загрузки уровня. Это снижает общую пропускную способность, но это не то, что вы оптимизируете.
Слёске

2
@Sleske - то, что вы говорите, правда. Тем не менее, запуск GC между уровнями является решением проблемы с полосой ... и не решает проблему задержки, если уровни занимают достаточно много времени, так что вам все равно нужно запустить GC во время уровня. Лучше использовать параллельный (с низкой паузой) сборщик мусора ... если платформа его поддерживает.
Стивен С

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

@Kirk - «Случайные вызовы System.gc () часто приводят к высоким издержкам GC». , Я знаю это. Как и любой, кто прочитал и понял мой ответ.
Стивен С

@Kirk - «Не совсем уверен, что вы имеете в виду ...» - я имею в виду программы, в которых «правильное» поведение программы зависит от GC, запущенного в определенное время; например, чтобы выполнить финализаторы или сломать WeakReferences или SoftReferences. Это действительно плохая идея ... но это то, о чем я говорю. Смотрите также ответ Стивена Шланскера.
Стивен С

47

Кажется, многие люди говорят тебе не делать этого. Я не согласен. Если после большого процесса загрузки, такого как загрузка уровня, вы считаете, что:

  1. У вас есть много объектов, которые недоступны и, возможно, не были получены. и
  2. Вы думаете, что пользователь может смириться с небольшим замедлением в этой точке

вызов System.gc () не причинит вреда. Я смотрю на это как inlineключевое слово c / c ++ . Это просто намек на то, что вы, разработчик, решили, что время / производительность не так важны, как обычно, и что некоторые из них могут быть использованы для восстановления памяти.

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

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


3
+1 для GC, анализируя утечки памяти. Обратите внимание, что информация об использовании кучи (Runtime.freeMemory () и др.) Действительно имеет смысл только после форсирования GC, иначе это будет зависеть от того, когда система в последний раз пыталась запустить GC.
Слёске

4
нет никакого вреда в вызове System.gc (), это может потребовать stop the worldподхода, и это реальный вред, если это произойдет
bestsss

7
Там является вред в вызове сборщика мусора в явном виде. Вызов GC в неправильное время тратит впустую циклы процессора. У вас (программиста) недостаточно информации, чтобы определить, когда наступит подходящее время ... но у JVM есть.
Стивен С.

Jetty делает 2 вызова System.gc () после запуска, и я редко видел, чтобы это имело значение.
Кирк

Ну, разработчики Jetty имеют ошибку. Это будет иметь значение ... даже если разницу трудно измерить.
Стивен С

31

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

(Следующие комментарии относятся к Hotspot, работающему в Linux с коллектором CMS, где я уверен, говоря, что System.gc()на самом деле он всегда вызывает полную сборку мусора).

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

  2. В том же ключе, что и в # 1, если вы внимательно следите за использованием кучи, вы хотите иметь точное представление о том, каково ваше базовое использование памяти. Если первые 2 минуты времени безотказной работы вашего приложения полностью инициализируются, ваши данные будут испорчены, если вы не заставите (хм ... «предложить») полный сбор данных.

  3. У вас может быть приложение, которое разработано так, чтобы никогда не рекламировать что-либо для постоянного поколения, пока оно работает. Но, возможно, вам нужно заранее инициализировать некоторые данные, которые не настолько велики, чтобы автоматически переходить к постоянному поколению. Если вы не вызовете System.gc () после того, как все настроено, ваши данные могут находиться в новом поколении, пока не придет время для их продвижения. Внезапно ваше сверхпопулярное приложение с малой задержкой и низким ГХ получает огромный (условно говоря) штраф за задержку за продвижение этих объектов во время обычных операций.

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


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

11

Это очень утомительный вопрос, и я чувствую, что многие выступают против Java, несмотря на то, насколько он полезен для языка.

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

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

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

Позвольте мне рассмотреть аргументы этой темы.

  1. Это неэффективно:

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

  1. Это всегда плохая практика и указывает на неработающий код.

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

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

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

  1. Это не обычный случай использования:

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

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

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

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

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

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

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


9

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

Звонить System.gc()- это все равно что пинать ГК. Это означает: «все эти тщательно настроенные параметры, эти умные организации, все усилия, которые вы просто вкладываете в распределение и управление объектами таким образом, чтобы все прошло гладко, ну, просто отбросьте всю партию и начинайте с нуля». Это может улучшить производительность, но в большинстве случаев это просто снижает производительность.

Для System.gc()надежного использования (*) вам необходимо знать, как работает ГХ, во всех его мелких деталях. Такие детали могут немного измениться, если вы используете JVM от другого поставщика, или следующую версию от того же поставщика, или ту же JVM, но с немного другими параметрами командной строки. Так что это редко хорошая идея, если только вы не хотите решить конкретную проблему, в которой вы контролируете все эти параметры. Отсюда и понятие «плохой практики»: это не запрещено, метод существует, но он редко окупается.

(*) Я говорю об эффективности здесь. System.gc()никогда не сломает правильную программу на Java. Он также не вызовет дополнительной памяти, которую JVM не могла бы получить иначе: перед броском OutOfMemoryErrorJVM выполняет свою работу System.gc(), даже если в качестве последнего средства.


1
+1 за упоминание, что System.gc () не предотвращает OutOfMemoryError. Некоторые люди верят в это.
Слёске

1
На самом деле, это может предотвратить OutOfMemoryError из-за обработки мягких ссылок. SoftReferences, созданные после последнего запуска GC, не собираются в реализации, которую я знаю. Но это детали реализации, которые могут быть изменены в любое время, и это своего рода ошибка, на которую не стоит полагаться.
Maaartinus

8

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

Много лет назад я работаю над генератором отчетов,

  • Была единственная нить
  • Прочитать «запрос отчета» из очереди
  • Загружены данные, необходимые для отчета из базы данных
  • Сгенерировал отчет и отправил его по электронной почте.
  • Повторяется вечно, спит, когда не осталось невыполненных запросов.
  • Он не использовал повторно какие-либо данные между отчетами и не делал никакого обналичивания.

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

Глядя на вышеприведенный план процесса, становится ясно, что.

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

Таким образом, очевидно, что выполнение GC стоит, когда очередь запросов пуста; в этом не было недостатка.

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

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

Мы никогда не обнаруживали установку, которая не приносила пользы - принудительный запуск GC каждый раз, когда рабочая очередь была пуста.

Но, давайте проясним, что вышеупомянутое не является частым случаем.


3

Может быть, я пишу дрянной код, но я понял, что щелкнуть значок корзины в IDE Eclipse и NetBeans - это «хорошая практика».


1
Это может быть так. Но если Eclipse или NetBeans были запрограммированы на System.gc()периодический вызов , вы, вероятно, найдете поведение раздражающим.
Стивен С.

2

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

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

Один пример, приведенный здесь, попал в мусорную корзину в вашей IDE. Если вы отправляетесь на встречу, почему бы не ударить ее. Накладные расходы не повлияют на вас, и куча может быть очищена, когда вы вернетесь. Сделайте это в производственной системе, и частые звонки на сбор приведут к полной остановке! Даже случайные вызовы, например, сделанные RMI, могут негативно сказаться на производительности.


3
«Реальность такова, что виртуальная машина никогда не будет игнорировать вызов System.gc ()». - Неверно. Читайте о -XX: -DisableExplicitGC.
Стивен С.

1

Да, вызов System.gc () не гарантирует его выполнения, это запрос к JVM, который может быть проигнорирован. Из документов:

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

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

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


<stroke> Но также из Javadoc: _ Когда элемент управления возвращается из вызова метода, виртуальная машина сделала все возможное, чтобы утилизировать все отброшенные объекты, что я считаю более обязательной формой того, о чем вы писали. </ stroke > Винт, есть сообщение об ошибке, вводящее в заблуждение. Кто лучше знает, каков вред намека на JVM?
zneak

1
Вред в том, что сбор в неподходящее время может сильно замедлить процесс. Намек, который вы даете, вероятно, плохой. Что касается комментария «лучшее из возможного», попробуйте его и посмотрите на инструмент, подобный JConsole. Иногда , нажав на кнопку «Выполнить» GC ничего не делает
Том

Извините, что не согласен, но вызов System.gc () в OpenJDK и все, что на его основе (например, HP) всегда приводит к циклу сбора мусора. На самом деле, это также верно и для реализации IBM J9
Кирк

@Kirk - Неверно: Google, и читайте о -XX: -DisableExplicitGC.
Стивен С

0

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

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

Однако то, поможет ли это или повредит (или ничего не сделает), сильно зависит от платформы (как определено выше).

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


0
  1. Поскольку объекты динамически распределяются с помощью оператора new,
    вам может быть интересно, как такие объекты уничтожаются и их
    память освобождается для последующего перераспределения.

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

  3. Java использует другой подход; он обрабатывает освобождение для вас автоматически.
  4. Техника, которая выполняет это, называется сборкой мусора. Это работает так: когда не существует ссылок на объект, предполагается, что этот объект больше не нужен, и память, занятая объектом, может быть восстановлена. Нет явной необходимости уничтожать объекты, как в C ++.
  5. Сборка мусора происходит спорадически (если вообще происходит) во время выполнения вашей программы.
  6. Это не произойдет просто потому, что существует один или несколько объектов, которые больше не используются.
  7. Кроме того, разные реализации Java во время выполнения будут использовать разные подходы к сборке мусора, но по большей части вам не нужно думать об этом при написании своих программ.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.