Как передать объект для сборки мусора python?

#python #reference #garbage-collection

#python #ссылка #сборка мусора

Вопрос:

В SO есть несколько потоков по сборке мусора Python, и после прочтения примерно пяти, плюс некоторого документа в строке, я все еще не уверен в том, как работает сборка мусора и как я должен управлять объектами, которые я не использую. На самом деле, где-то я читал, что не следует ничего делать со сбором мусора, другие говорят, что нужно del создавать объекты, в то время как другие снова объясняют, что для Python достаточно отменить ссылку на объект, чтобы собрать его как мусор.

Итак, рискуя создать дубликат, я задам вопрос снова, но по-другому, надеясь получить более полную и ясную информацию.

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

Теперь, как мне заставить этот Person() экземпляр «умереть» (предполагая, что многие из этих экземпляров будут созданы, и я не хочу, чтобы эти экземпляры зависали как призраки)?

Есть несколько способов, которыми я могу ссылаться на объект:

 john = Person('john')
  

или

 people = []
people.append(Person('john'))
  

или

 people = {}
people['john'] = Person('john')
  

Каков наилучший способ поддерживать мою программу в чистоте, оптимально освобождая ресурсы? И каков наилучший способ ссылаться на мой объект, чтобы я мог контролировать удаление объекта?

Комментарии:

1. Проверьте модуль gc: docs.python.org/library/gc.html

2. Короткий ответ: вы этого не делаете. Он принимает его сам, когда вы больше не используете (имеете ссылку на) его. Или, возможно, позже или никогда. GC не является детерминированным, единственная гарантия заключается в том, что у вас не закончится память, если есть мусор для повторного использования (за исключением некоторых случаев с консервативными GCS, но ни в Python, ни в каком другом языке, управляемом памятью, они не должны использоваться; только языки с арифметикой указателей или способом преобразования указателей в целые числа и т.д. Нуждаются в них). И если вы не понимаете, что и почему вам обычно вообще не нужно беспокоиться, вы должны оставить все как есть.

3. Этот вопрос в равной степени может относиться к ruby, Smalltalk, Java, C # или VB6 и, возможно, многим другим.

Ответ №1:

Возможно, это также может помочь:

 >>> # Create a simple object with a verbose __del__ to track gc.
>>> class C:
...     def __del__(self):
...         print "delete object"
... 
>>> c = C()
>>> # Delete the object c successfully.
>>> del c
delete object
>>> # Deletion of an object when it go out of the scope where it was defined.
>>> def f():
...     c = C()
...
>>> f()
delete object
>>> c = C()
>>> # Create another reference of the object.
>>> b = c
>>> # The object wasn't destructed the call of del only decremented the object reference. 
>>> del c
>>> # Now the reference counter of the object reach 0 so the __del__ was called. 
>>> del b
delete object
>>> # Create now a list that hold all the objects.
>>> l = [C(), C()]
>>> del l
delete object
delete object
>>> # Create an object that have a cyclic reference.
>>> class C:
...     def __init__(self):
...         self.x = self
...     def __del__(self):
...         print "delete object"
... 
>>> c = C()
>>> # Run the garbage collector to collect object.
>>> gc.collect()
9
>>> # the gc.garbage contain object that the gc found unreachable and could not be freed.  
>>> gc.garbage
[<__main__.C instance at 0x7ff588d84368>]
>>> # Break the cyclic reference.
>>> c.x = None
>>> # And now we can collect this object.
>>> del c
delete object
>>> # Create another object with cyclic reference.
>>> c = C()
>>> # When closing the interactive python interpreter the object will be collected.
delete object
  

Ссылки: методdel; модуль gc; модуль weakref

Комментарии:

1. Спасибо 🙂 все ответы были действительно хорошими, я выбрал Quamrana, потому что он дал ответ, который больше соответствовал примеру вопроса.

2. @Benjamin: Рад, что вы получили свой ответ 🙂

Ответ №2:

Ничто из этого на самом деле не имеет никакого отношения к сборке мусора.

Основной метод управления памятью Python использует подсчет ссылок.

Во всех приведенных выше случаях Python ведет подсчет всех ссылок на объект, и когда таковых не остается, объект удаляется (аналогично std::shared_pointer в C ).

Ссылки уменьшаются, когда

  1. объект, содержащий их, либо явно удаляется (через del )
  2. или выходит за рамки (смотрите также здесь (особенно пример 8)).

В вашем случае это относится либо к john объекту, либо к любому из people контейнеров. Они выходят за пределы области видимости в конце функции, которая их создала (при условии, что они не return редактируются вызывающей функцией). В подавляющем большинстве случаев вы можете просто позволить им выйти за пределы области видимости — только когда вы создаете действительно тяжелые объекты или коллекции — скажем, внутри большого цикла — вы можете рассмотреть возможность явного использования del .

Сборка мусора действительно вступает в игру только при наличии циклов ссылок — например, когда объект ссылается на самого себя. Нравится:

 a = []
a.append(a)
  

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

Комментарии:

1. Спасибо 🙂 все ответы были действительно хорошими, я выбрал Quamrana, потому что он дал ответ, который больше соответствовал примеру вопроса.

Ответ №3:

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

Несколько примеров:

 person = Person('john')
person = Person('james')
# Whoops! 'john' has died!

people = []
people.append(Person('john'))
# ...
# All 'Persons' live in people
people = []
# Now all 'Persons' are dead (including the list that referenced them)

class House():
    def setOwner(self, person):
        self.owner = person

house.setOwner(people[0])
# Now a House refers to a Person
people = []
# Now all 'Persons' are dead, except the one that house.owner refers to.
  

Я предполагаю, что вам нужно это:

 people = {}
people['john'] = Person('john')

def removePerson(personName):
    del people[personName]

removePerson('john')
  

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

Возможно, вам придется очень тщательно продумать концепцию человека, который создается, а затем умирает: после создания, как человек сначала взаимодействует с симуляцией. После смерти, как вы должны распутать ссылки? (Для человека нормально ссылаться на другие материалы, такие вещи, как House в моем примере, которые сохранят человеку жизнь. Другие объекты могут содержать только имя пользователя).

Ответ №4:

Предыдущие ответы верны, но вот то, что рекомендуется в соответствии с Документом python 3.7:

«Python выполняет автоматическое управление памятью (подсчет ссылок для большинства объектов и сбор мусора для устранения циклов). Память освобождается вскоре после того, как последняя ссылка на нее была удалена.»

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

      del self.someInstanceOfyourClass
             gc.collect()
  

вот простой пример https://github.com/nanoseconds/PythonTest/blob/master/test.py