Почему вы не явного вызова завершения () или запустить сборщик мусора?

голоса
27

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

Задан 26/08/2008 в 20:46
источник пользователем
На других языках...                            


7 ответов

голоса
42

Короткий ответ: сбор мусора Java очень тонко настроенный инструмент. System.gc () является кувалдой.

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

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

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

В документе ВС вы думаете здесь: Java SE 6 HotSpot ™ Virtual Machine Garbage Collection Tuning

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

Ответил 26/08/2008 в 22:54
источник пользователем

голоса
4

Не связывайтесь с финализаторами.

Переключитесь дополнительным сбор мусора.

Если вы хотите помочь сборщика мусора, обнулить от ссылок на объекты, которые больше не нужны. Меньше путь следования = более явно мусор.

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

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

Рассмотрите возможность использования мягких ссылок. Если вы не знаете, что мягкие ссылки, имеют прочитанный в Javadoc для java.lang.ref.SoftReference

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

Наконец, если вы действительно не можете терпеть использование GC Realtime Java.

Нет, я не шучу.

Эталонная реализация является бесплатным для загрузки и Питера Dibbles книгу из ВС действительно хорошее чтение.

Ответил 26/08/2008 в 23:53
источник пользователем

голоса
3

Насколько финализаторами идти:

  1. Они практически бесполезны. Они не гарантируют назвать своевременно, или в самом деле, на всех (если GC никогда не работает, ни будет ни финализаторами). Это означает, что вы вообще не должны полагаться на них.
  2. Финализаторы не гарантируется идемпотентным. Сборщик мусора занимает большую осторожность , чтобы гарантировать , что он никогда не будет вызывать finalize()больше , чем один раз на том же объекте. С хорошо написанные объекты, это не имеет значения, но с плохо написанными объекты, призывая завершить несколько раз может вызвать проблемы (например , двойное освобождение родного ресурса ... аварии).
  3. Каждый объект , который имеет finalize()метод должен также обеспечивать close()(или аналогичный) метод. Это функция , которую вы должны звонить. например, FileInputStream.close(). Там нет причин , чтобы быть вызова , finalize()когда у вас есть более подходящий метод , который будет предназначен для вызова вами.
Ответил 27/08/2008 в 17:16
источник пользователем

голоса
1

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

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

SomeStream s = null;
...
try{
   s = openStream();
   ....
   s.io();
   ...
} finally {
   if (s != null) {
       s.close();
       s = null;
   }
}

Это становится еще более сложным , если вы пишете свои собственные классы , которые работают с помощью JNI и открытых ручек. Вы должны убедиться , что ручки закрыты (освобождены) , и что это будет происходить только один раз. Часто забывают OS ручка Desktop J2SE является Graphics[2D]. ДажеBufferedImage.getGrpahics() потенциально может вернуть вам ручку , которая указывает на видео драйвер ( на самом деле держит ресурс на GPU). Если вы не отпустите его самостоятельно и оставить его сборщик мусор , чтобы сделать работу - вы можете обнаружить странные OutOfMemory и так ситуацию , когда вы выбежали видеокарты отображаются растровыми изображениями , но все еще есть много памяти. В моем опыте это происходит довольно часто в узких петлях работа с графическими объектами (извлечение миниатюр, масштабирование, заточка вы называете его).

В основном GC не берет на себя ответственность программистов правильного управления ресурсами. Он принимает только заботиться о памяти, и больше ничего. Вызывающие близко () ИМХО Stream.finalize будет лучше реализовано метанием исключения нового RuntimeError ( «мусор сбора потока, который все еще остается открытым»). Это сэкономит часы и дни отладки и очистки коды после того, как неряшливые любители оставили концы проиграют.

Счастливое кодирование.

Мир.

Ответил 22/03/2011 в 08:25
источник пользователем

голоса
1

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

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

Если бы вы знали больше о том, что GC держал внутри, то вы можете быть в состоянии принимать более обоснованные решения, но тогда вы пропустили преимущества ГК.

Ответил 26/08/2008 в 20:55
источник пользователем

голоса
0

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

Многие люди используют финализаторы делать такие вещи, как близко штепсельных соединений или удаление временных файлов. Поступая таким образом вы сделаете ваше поведение приложения непредсказуемы и привязали к JVM, когда собирается GC вашего объекта. Это может привести к «из памяти» сценарии, а не из-за Java Heap истощаются, а из-за системы, работающие из ручек для конкретного ресурса.

Еще одна вещь, чтобы иметь в виду, что введение вызовы System.gc () или такие молоты могут показывать хорошие результаты в своей среде, но они не обязательно переводить на другие системы. Не все работает тот же JVM, есть много, SUN, IBM J9, BEA JRockit, Harmony, OpenJDK, и т.д ... Это JVM всех соответствующих стандартов JCK (те, которые были официально протестированы, что есть), но есть много свобода, когда дело доходит до создания вещей быстро. GC является одной из тех областей, которые каждый вкладывает в сильно. Используя молоток часто раз уничтожить эти усилия.

Ответил 27/08/2008 в 16:39
источник пользователем

голоса
0

GC делает много оптимизации относительно того, когда должным образом завершить вещи.

Так что, если вы не знакомы с тем, как GC действительно работает и как это теги поколений, вручную вызова завершить или начать GC'ing, вероятно, пострадал производительность, чем помочь.

Ответил 26/08/2008 в 20:49
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more