Сборка мусора для простого класса python - PullRequest
1 голос
/ 25 мая 2020

Я пишу класс python следующим образом:

class MyImageProcessor:
   def __init__ (self, image, metadata):
     self.image=image
     self.metadata=metadata

И image, и metadata являются объектами класса, написанного моим коллегой. Теперь мне нужно убедиться, что память не тратится. Я думаю об определении такого метода quit(),

  def quit():
    self.image=None
    self.metadata=None
    import gc
    gc.collect()

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

В качестве альтернативы я мог бы переименовать quit () во встроенную __exit__() и предложить пользователям использовать синтаксис «with». Но мой вопрос больше о том, действительно ли инструкции в quit () выполняют работу по сборке мусора, которая может понадобиться в этой ситуации.

Спасибо за вашу помощь.

Ответы [ 3 ]

4 голосов
/ 28 мая 2020

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

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

Подобно конструкторам объектов (__init__()), которые вызываются при создании объекта, вы можете определить деструкторы (__del__()), которые выполняются на удаление объекта (обычно, когда счетчик ссылок падает до 0). Согласно этой статье , в python они не столь необходимы в C ++, потому что Python имеет сборщик мусора, который автоматически обрабатывает управление памятью. Вы можете проверить эти примеры тоже.

Надеюсь, это поможет :)

3 голосов
/ 03 июня 2020

Нет необходимости в quit() (при условии, что вы используете C -based python).

Python использует два метода сборки мусора, как указано в других ответах.

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

From https://devguide.python.org/garbage_collector/:

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

Вы можете получить информацию о текущих счетчиках ссылок для объекта, используя sys.getrefcount(x), но на самом деле , зачем заморачиваться.

Второй способ через сборку мусора (gc). [Подсчет ссылок - это тип сборки мусора, но python специально называет этот второй метод «сборкой мусора», поэтому мы также будем использовать эту терминологию. ] Это предназначено для поиска тех мест, где счетчик ссылок не равен нулю, но объект больше не доступен. («Циклы ссылок») Например:

class MyObj:
    pass
x = MyObj()
x.self = x

Здесь x относится к самому себе, поэтому фактическое количество ссылок для x больше 1. Вы можете вызвать del x, но это просто удалит его. из вашей области действия: он живет, потому что «кто-то» все еще ссылается на него.

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

Вернемся к вашему вопросу: вам не нужно иметь объект quit (), потому что, как только ваш объект MyImageProcessor будет вне области действия, он уменьшит счетчики ссылок для image и metadata. Если это обнуляет их, они освобождаются. Если этого не происходит, что ж, их использует кто-то другой.

Сначала вы устанавливаете для них значение «Нет», просто уменьшает счетчик ссылок сразу после , но когда MyImageProcessor выходит за пределы области видимости, он не будет снова уменьшать счетчик ссылок, потому что MyImageProcessor не дольше хранит изображения или объекты метаданных! Итак, вы просто явно делаете то, что python делает для вас уже бесплатно: ни больше, ни меньше.

Вы не создали цикл, поэтому ваш вызов gc.collect() вряд ли что-то изменит.

Проверьте https://devguide.python.org/garbage_collector/, если вас интересуют более земные подробности.

0 голосов
/ 31 мая 2020

Не уверен, имеет ли это смысл, но для моего журнала c вы могли бы

Использовать:

g c .get_count ()

до и после

g c .collect ()

, чтобы увидеть, было ли что-то удалено.

какие значения count0, count1 и count2, возвращаемые Python г c .get_count ()

...