Skip to content

Память

Как работает

  • Все работает на ссылках на память:

    list_1 = [1, 2]
    list_2 = list_1
    list_1 = None 
    # list_2 = [1, 2]
    

Счетчик Ссылок

  • Нет ссылок - чистим память
  • Не ищет циклические ссылки

Garbage Collector

  • Ищет циклические ссылки
  • Циклические ссылки: list_ = [1,]; list_.append(list_)
  • Помещает циклические ссылки + объекты, которые давно не чистились, в генерации / поколения
  • 3 генерации
    • Нужно для экономии ресурсов
    • Различаются по длительности жизни (кол-во проверок на наличие ссылок)

Intering

  • [-5, 256] - одна и та же область памяти: a1 = 1; a2 = 1; a1 is a2
  • Аналогично: Строки (латиница + _ + цифры), пустые кортежи
  • sys.intern - функ для ссылки на один и тот же объект

API

  • id - айди объекта в памяти
  • sys.getrefcount - кол-во ссылок + 1
  • gc.get_refferers(obj) - список кто ссылается на объект
    • Глобальные объекты будут всегда в globals
  • __del__ - вызывается когда объект будет удален из памяти

WeakRef

  • Слабые ссылки = кол-во ссылок на объект не увеличивается:
c = Cls()
d = weakref.ref(c)
d() is C
sys.getrefcount(c) == 2
  • Объект Удаляется если все ссылки слабые
c = Cls()
d = weakref.ref(c)
c = 5
d() is None

Юзкейсы

GC цикл. ссылок

c = Cls()
c.c = c
c = None
## No Cls.__del__ called
gc.collect()
## Cls.__del__ called

c.c = weakref.proxy(c)
c = None
## Cls.__del__ called

List of weak-refs / Observer Pattern

list_ = []
for i in range(3):
  list_.append(weakref.ref(Cls(i)))
## Cls.__del__ called 3 times

c1 = Cls()
c2 = Cls()
list_ = []
list_.append(weakref.ref(c1))
list_.append(weakref.ref(c2))
del c1
## list_ == [None, c2]

Кеш: WeakKeyDictionary, WeakValueDictionary, WeakSet

dict_ = WeakKeyDictionary()
c = Cls()
dict_[c] = 2
c = None 
## Cls.__del__ called
## dict_ is empty!

Материалы