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

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

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

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

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

9 Solutions collect form web for “Почему методы сбора мусора Java и Python отличаются?”

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

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

Кроме того, Garbage Collection можно сделать в отдельном потоке (хотя это может быть немного сложно). На машинах с большим количеством ОЗУ и для процессов, которые используют память только медленно, вы, возможно, не захотите делать GC вообще! Сопоставление ссылок было бы немного недостатком в плане производительности …

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

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

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

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

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

Даррен Томас дает хороший ответ. Однако одна большая разница между подходами 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, который может работать в отдельном потоке и имеет все эти безумные оптимизации и т. Д. Различия в том, как вы написать свой код должен быть незначительным и в идеале не существует.

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

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

[Это также является причиной того, что gc может быть быстрее, чем malloc / free]

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

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

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

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

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

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

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

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

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

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

Поздно в игре, но я думаю, что одним из важных обоснований для RC в python является его простота. См. Это письмо от Alex Martelli , например.

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

  • Python: как я могу выполнить файл jar через скрипт python
  • Команда Storm не работает с NoClassDefFoundError после добавления jsoup в соответствии с указанной зависимостью
  • Библиотека для управления файлами S-Record и Intel HEX 16
  • Загрузить пользовательскую модель NER Stanford CoreNLP
  • Какой язык проще всего и быстрее работает с XML-контентом?
  • Отображение списка на Java так же изящно, как в Python
  • Различное поведение одного и того же регулярного выражения в Python и Java
  • Как определить, установлена ​​ли java на систему через python?
  •  
    Interesting Posts for Van-Lav

    Python 3.2 странная ошибка с типом диапазона в списке

    Встроенная функция суммы Python против производительности цикла

    Django: Как установить начальные значения для поля в встроенной модели Formet?

    Подключение к узлу, указанному в ~ / .ssh / config при использовании Fabric

    Доступ к объектам автоматизации Microsoft с Python

    Альтернативы регулярного выражения в Python

    Самый короткий способ создания объекта с произвольными атрибутами в Python?

    Можно ли настроить Python для кэширования поиска в каталоге sys.path?

    conda и pip не работают вообще

    GAE и Facebook Connect: как получить возраст и пол пользователя?

    Структура, доступная по названию атрибута или параметрам индекса

    Как преобразовать матрицу совпадения в разреженную матрицу

    Как получить PID по имени процесса в Python?

    Как обнаружить столкновение объектов в Pygame?

    Поддерживает ли JavaScript поддержку массивов / списков, таких как Python?

    Python - лучший язык программирования в мире.