Почему методы сбора мусора Java и Python отличаются?

голоса
47

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

Но, в Java, то GC (сборщик мусора) уничтожает объекты, которые больше не являются используемые в определенное время.

Почему Java выбирают эту стратегию и какова польза от этого?

Это лучше, чем подход Python?

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


9 ответов

голоса
43

Есть недостатки использования подсчета ссылок. Одним из самых упоминаемых в циклические ссылки: Пусть A Ссылки B, B ссылается на С и С ссылается B. Если A должны были упасть свою ссылку на B, и В и С по-прежнему имеют счетчик ссылок 1, и не будут удалены с традиционным подсчетом ссылок. CPython (подсчет ссылок не является частью самого Python, но часть реализации C их) ловит циклические ссылки с отдельной подпрограммой сбора мусора, что она периодически запускается ...

Другой недостаток: Подсчет ссылок может сделать выполнение медленнее. Каждый раз, когда упоминается и разыменовывается объект, интерпретатор / VM должен проверить, чтобы увидеть, если число понизилось до 0 (а затем освободить, если он сделал). Сбор мусора не нужно делать это.

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

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

голоса
26

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

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

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

Кроме того, ссылка подсчета ГХ требует детектор цикла, чтобы очистить любые объекты в цикле, который не будет пойманной их счетчик ссылок в одиночку. Perl-5 не было детектора цикла в его реализации GC и может произойти утечка памяти, которая была циклической.

Исследование также было сделано , чтобы получить лучшее из обоих миров (раз низкая пауза, высокая пропускная способность ): http://cs.anu.edu.au/~Steve.Blackburn/pubs/papers/urc-oopsla-2003.pdf

Ответил 13/10/2008 в 02:42
источник пользователем

голоса
13

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

Например, я могу написать неаккуратно, без переносимого кода в CPython, таких как

def parse_some_attrs(fname):
    return open(fname).read().split("~~~")[2:4]

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

Таким образом, вы должны писать код, который выглядит

def parse_some_attrs(fname):
    with open(fname) as f:
        return f.read().split("~~~")[2:4]

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

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

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

голоса
8

Я думаю , что статья « Теория и практика Java: Краткая история сборки мусора » от IBM поможет объяснить некоторые из вопросов , которые вы имеете.

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

голоса
5

Сбор мусора быстрее (больше времени эффективно) , чем подсчет ссылок, если у вас есть достаточно памяти. Например, копирование дс обходит «живые» объекты и копирует их в новое пространство, и может вернуть все «мертвые» объекты в одном шаге, пометив всю область памяти. Это очень эффективно, если у вас достаточно памяти. Поколенческие коллекции используют знание , что «большинство объектов умирают молодые»; часто лишь несколько процентов объектов должны быть скопированы.

[Это также причина, почему дс может быть быстрее, чем таНос / бесплатно]

Подсчет ссылок гораздо больше места эффективный, чем сбор мусора, поскольку Использование памяти в тот самый момент он получает недостижим. Это хорошо, когда вы хотите прикрепить финализаторы к объектам (например, закрыть файл, если объект File получает недостижим). Система подсчета ссылок может работать даже тогда, когда только несколько процентов памяти свободно. Но расходы на управление, чтобы иметь необходимость увеличение и уменьшение счетчик к каждой из уступки указателя стоит много времени, и какое-то сбор мусора по-прежнему необходимо, чтобы вернуть циклы.

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

Ответил 16/09/2008 в 17:38
источник пользователем

голоса
3

Один большой недостаток кальки GC Java является то, что время от времени он будет «остановить мир» и заморозить приложение в течение относительно длительного времени, чтобы сделать полный GC. Если куча большая и дерево объектов комплекса, она замерзает в течение нескольких секунд. Кроме того, каждый полный GC посещает все дерево объектов снова и снова, то, что, вероятно, весьма неэффективно. Еще одним недостатком, как Java делает GC является то, что вы должны сказать, что размер JVM кучи вы хотите (если по умолчанию не достаточно хорошо); виртуальная машина проистекает из того, что значение нескольких пороговых значений, которые будут вызывать процесс GC, когда есть слишком много мусора укладки в кучах.

Я предполагаю, что это на самом деле основная причина рывков чувства Android (на основе Java), даже на самом дорогих мобильных телефонах, по сравнению с гладкостью прошивки (на основе ObjectiveC, и с помощью RC).

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

Ответил 19/10/2011 в 19:40
источник пользователем

голоса
2

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

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

Ответил 05/09/2008 в 21:03
источник пользователем

голоса
2

Последнее Sun Java VM на самом деле есть несколько алгоритмов GC, которые вы можете настроить. Спецификации Java VM намеренно опущены определение фактического поведения GC, чтобы различные (и несколько) алгоритмов GC для различных виртуальных машин.

Например, для всех людей , которые не любят «стоп-мире» подход Sun Java VM поведения GC по умолчанию, есть VM , таких как WebSphere Real Time IBM, которая позволяет в режиме реального времени приложение для запуска на Java.

Поскольку спецификации Java VM является общедоступной, не существует (теоретически) ничто не мешает никому из реализации Java VM, использующий алгоритм GC CPython в.

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

голоса
1

В конце игры, но я думаю , что одно существенное обоснование для RC в питона является его простота. Смотрите эту электронную почту Алекс Мартелли , например.

(Я не мог найти ссылку вне кэша Google, даты электронной почты от 13 октября 2005 года по списку питона).

Ответил 22/10/2009 в 02:11
источник пользователем

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