#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 ).
Ссылки уменьшаются, когда
- объект, содержащий их, либо явно удаляется (через
del
) - или выходит за рамки (смотрите также здесь (особенно пример 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