Сопоставляют ли циклы ссылок в Java замедлять сборку мусора или влияют на память / производительность? [Дубликат]

Это S из SOLID : Единая ответственность.

thread олицетворяет текущий контекст (как в контексте выполнения: стек стека, идентификатор потока и т. д.) асинхронного выполнения части код. То, что кусок кода в идеале должен быть одной и той же реализацией, будь то синхронный или асинхронный .

Если вы объедините их вместе в одна реализация, вы даете результирующему объекту две несвязанные причины изменения:

  1. обработка потоков в вашем приложении (т. е. запрос и изменение контекста выполнения)
  2. Алгоритм
  3. , реализованный частью кода (runnable part)

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

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

В контексте Java , поскольку средство уже существует, возможно, легче начать прямо с самостоятельных классов Runnable и передать свои экземпляры в Thread (или Executor) экземпляров. Как только использовал для этого шаблона, его труднее использовать (или даже читать), чем простой исполняемый поток.

132
задан Marek J 17 August 2016 в 10:31
поделиться

8 ответов

GC GC GC рассматривает объекты «мусор», если они недоступны через цепочку, начинающуюся с корня коллекции мусора, поэтому эти объекты будут собраны. Даже если объекты могут указывать друг на друга, чтобы сформировать цикл, они все еще мусор, если они отрезаны от корня.

См. Раздел о недоступных объектах в Приложении A: Правда о сборке мусора в Производительность платформы Java: стратегии и тактика для деталей gory.

132
ответ дан Holger 18 August 2018 в 23:31
поделиться
  • 1
    У вас есть ссылка на это? Трудно проверить это. – tangens 15 December 2009 в 21:38
  • 2
    Я добавил ссылку. Вы также можете переопределить метод finalize () объекта, чтобы узнать, когда он будет собран (хотя это единственное, что я рекомендую использовать finalize () for). – Bill the Lizard 15 December 2009 в 21:40
  • 3
    Чтобы прояснить этот последний комментарий ... поставьте отладочную инструкцию print в методе finalize, который выводит уникальный идентификатор объекта. Вы сможете увидеть все объекты, которые связывают друг с другом. – Bill the Lizard 15 December 2009 в 21:45
  • 4
    & quot; ... достаточно умный, чтобы распознавать ... & quot; звучит запутанно. GC не должны распознавать циклы - они просто недостижимы, поэтому мусор – Alexander Malakhov 9 August 2011 в 02:59
  • 5
    @tangens "У вас есть ссылка для этого? & quot; в дискуссии о сборке мусора. Лучший. Пун. Когда-либо. – Michał Kosmulski 30 January 2013 в 22:00

Сбор мусора обычно не означает «очистить какой-либо объект, если ничто иное не указывает на этот объект» (это подсчет ссылок).

Итак, в вашем примере после того, как a, b и c выходят из сферы действия, они могут быть собраны GC, так как вы больше не могут обращаться к этим объектам.

0
ответ дан Amnon 18 August 2018 в 23:31
поделиться
  • 1
    «Сбор мусора грубо означает поиск объектов, которые не могут быть достигнуты из программы». В большинстве алгоритмов GC это наоборот. Вы начинаете с корней GC и видите, что можете найти, остальное считается неучтенным мусором. – Fredrik 15 December 2009 в 21:42
  • 2
    Подсчет ссылок является одной из двух основных стратегий реализации мусора. (Другой отслеживает.) – Jörg W Mittag 16 December 2009 в 00:21
  • 3
    @ Jörg: В большинстве случаев сегодня, когда люди говорят о сборщиках мусора, они ссылаются на коллекционеров, основанных на каком-то алгоритме mark'n'sweep. Считывание ссылок - это, как правило, то, за что вы застряли, если у вас нет сборщика мусора. Это правда, что подсчет ref является в некотором смысле стратегией сбора мусора, но сегодня практически нет gc, которая строится поверх нее, поэтому говорят, что стратегия gc просто путает людей, потому что на практике она больше не является gc но альтернативный способ управления памятью. – Fredrik 16 December 2009 в 13:12

yes Java Сборщик мусора обрабатывает циркулярную ссылку!

How?

Существуют специальные объекты, называемые корнями сбора мусора (корни GC).

Простое Java-приложение имеет следующие корни GC:

  1. Локальные переменные в основном методе
  2. Основной поток
  3. Статические переменные основного класса

enter image description here [/g1]

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

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

Таким образом, если какой-либо объект недоступен из корней GC (даже если он является самореферентным или циклическим), он

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

enter image description here [/g2]

Источник: Управление памятью Java

109
ответ дан Aniket Thakur 18 August 2018 в 23:31
поделиться
  • 1
    Отличное объяснение! Благодаря! :) – Jovan Perovic 30 April 2015 в 13:26
  • 2
    Спасибо, что связали эту книгу. Он полон большой информации об этой и других тем развития Java! – Droj 22 April 2016 в 14:02
  • 3
    На последнем снимке есть недоступный объект, но его часть в доступной части объектов. – La VloZ Merrill 16 August 2016 в 08:54

Билл ответил на ваш вопрос напрямую. Как сказал Амнон, ваше определение сбора мусора - это просто подсчет ссылок. Я просто хотел добавить, что даже очень простые алгоритмы, такие как сборка меток и подметания и копирования, легко обрабатывают циклические ссылки. Итак, ничего волшебного в этом нет!

0
ответ дан Claudiu 18 August 2018 в 23:31
поделиться

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

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

И эта простая стратегия имеет именно ту проблему, которую вы описываете: если ссылки A B и B ссылки A, то оба их подсчета ссылок могут никогда быть меньше 1, что означает, что они wil Я никогда не собираюсь собраться.

Существует четыре способа решения этой проблемы:

  1. Игнорировать. Если у вас достаточно памяти, ваши циклы малы и нечасты, а время выполнения короткое, возможно, вам удастся просто не собирать циклы. Подумайте о интерпретаторе сценария оболочки: сценарии оболочки обычно запускаются в течение нескольких секунд и не выделяют много памяти.
  2. Объедините свой счетный сборщик мусора с другим сборщиком мусора , который не работает У меня проблемы с циклами. CPython делает это, например: главный сборщик мусора в CPython является сборщиком подсчета ссылок, но время от времени трассировочный сборщик мусора запускается для сбора циклов.
  3. Обнаружение циклов. К сожалению, обнаружение циклов на графике является довольно дорогостоящей операцией. В частности, он требует почти столько же накладных расходов, что и коллекционер трассировки, поэтому вы могли бы использовать один из них.
  4. Не реализуйте алгоритм наивным образом, как вы и я: поскольку в 1970-х годах было разработано несколько довольно интересных алгоритмов, которые объединяют обнаружение циклов и подсчет ссылок в одной операции умным способом, который значительно дешевле, чем либо делать их как отдельно, либо делать трассирующий коллектор.

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

Поскольку цикл доступен только внутри себя, но недоступен из набора корней, он будет собран.

8
ответ дан Jörg W Mittag 18 August 2018 в 23:31
поделиться
  • 1
    Поскольку вопрос является специфичным для Java, я думаю, стоит упомянуть, что Java не использует подсчет ref и, следовательно, проблему несуществует. Также ссылка на wikipedia будет полезна как «дальнейшее чтение». В противном случае отличный обзор! – Alexander Malakhov 9 August 2011 в 04:48
  • 2
    Я только что прочитал ваши комментарии к сообщению Джерри Коффина, так что теперь я не уверен, что :) – Alexander Malakhov 9 August 2011 в 04:58

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

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

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

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

10
ответ дан Jerry Coffin 18 August 2018 в 23:31
поделиться
  • 1
    То, что вы описываете, является сборщиком трассировки. Существуют и другие виды коллекционеров. Особый интерес для этого обсуждения представляют опорные счетные коллекторы, которые do имеют проблемы с циклами. – Jörg W Mittag 16 December 2009 в 00:20
  • 2
    @ Jörg W Mittag: Конечно, правда, хотя я не знаю о (разумно текущей) JVM, которая использует подсчет ссылок, поэтому кажется маловероятным (по крайней мере для меня), что это имеет большое значение для исходного вопроса. – Jerry Coffin 16 December 2009 в 00:28
  • 3
    @ Jörg W Mittag: По крайней мере, по умолчанию я считаю, что Jikes RVM в настоящее время использует сборщик Immix, который является сборщиком трассировки на основе региона (хотя он также использует подсчет ссылок). Я не уверен, ссылаетесь ли вы на этот подсчет ссылок или на другой сборщик, который использует подсчет ссылок без трассировки (я бы предположил, что последний, поскольку я никогда не слышал о том, что Immix называет & recycler & quot;). – Jerry Coffin 16 December 2009 в 01:27
  • 4
    Я немного перепутался: Recycler был (был?) Реализован в Jalapeno, алгоритм, о котором я думал, который (был?) Реализован в Jikes - это Устный подсчет ссылок . Atlhough, конечно же, говорит, что Jikes использует тот или иной сборщик мусора, совершенно бесполезен, учитывая, что Jikes и особенно MMtk специально разработаны для быстрого развития и тестирования разных сборщиков мусора в пределах одной JVM. – Jörg W Mittag 16 December 2009 в 01:52
  • 5
    Уличный подсчет ссылок был разработан в 2003 году теми же людьми, которые разработали Immix в 2007 году, поэтому я думаю, что последнее, вероятно, заменило первое. УРК был специально разработан таким образом, чтобы его можно было сочетать с другими стратегиями, и на самом деле в документе УРК прямо упоминается, что УРК является лишь ступенчатым шагом к сборщику, который сочетает в себе преимущества отслеживания и подсчета ссылок. Думаю, что Иммикс - это коллекционер. Во всяком случае, Recycler является чистым счетным сборщиком ссылок, который тем не менее может обнаруживать и собирать циклы: WWW.Research.IBM.Com/people/d/dfb/recycler.html – Jörg W Mittag 16 December 2009 в 02:03

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

  • статические переменные
  • локальные переменные (включая все применимые «эти» ссылки), находящиеся в настоящее время в стеке работающего потока

Итак, в вашем случае, как только локальные переменные a, b и c выйдут из области действия в конце вашего метода, больше нет корней GC, которые прямо или косвенно содержат ссылку на любой из ваши три узла, и они будут иметь право на сбор мусора.

Ссылка TofuBeer имеет более подробную информацию, если вы этого хотите.

5
ответ дан Sbodd 18 August 2018 в 23:31
поделиться
  • 1
    "... в настоящее время в стеке работает поток ... & quot; разве это не сканирование стеков всех потоков, чтобы не повредить данные другого потока? – Alexander Malakhov 9 August 2011 в 05:05

Эта статья (больше не доступна) углубляется в сборщик мусора (концептуально ... существует несколько реализаций). Соответствующая часть вашего сообщения - «A.3.4 Unreachable»:

A.3.4 Недостижимый Объект переходит в недостижимое состояние, когда нет более сильных ссылок на него. Когда объект недоступен, он является кандидатом на сбор. Обратите внимание на формулировку: только потому, что объект является кандидатом на сбор, это не означает, что он будет немедленно собран. JVM может задерживать сбор до тех пор, пока не будет немедленно потребована память, потребляемая объектом.

4
ответ дан TofuBeer 18 August 2018 в 23:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: