Что делает "del" в точности?

Вот мой код:

from memory_profiler import profile

@profile
def mess_with_memory():
    huge_list = range(20000000)
    del huge_list
    print "why this kolaveri di?"

Это результат, когда я запускал его из интерпретатора:

Линия # Использование памяти Увеличение строки содержимого

 3      7.0 MiB      0.0 MiB   @profile
 4                             def mess_with_memory():
 5                             
 6    628.5 MiB    621.5 MiB       huge_list = range(20000000)
 7    476.0 MiB   -152.6 MiB       del huge_list
 8    476.0 MiB      0.0 MiB       print "why this kolaveri di"

Если вы заметили результат, создав огромный список, потребляемый 621,5 МБ, при удалении он просто высвободил 152,6 МБ. Когда я проверил docs, я нашел следующее утверждение:

the statement del x removes the binding of x from the namespace referenced by the local scope

Итак, я думаю, он не удалял сам объект, а просто отключал его. Но что он сделал в том, что он освободил столько места (152.6 МБ). Может кто-нибудь, пожалуйста, возьмите боль, чтобы объяснить мне, что здесь происходит?

Ответы

Ответ 1

Python - это собранный мусором язык. Если значение больше не "доступно" из вашего кода, оно в конечном итоге будет удалено.

Оператор del, как вы видели, удаляет привязку вашей переменной. Переменные - это не значения, они просто имена для значений.

Если эта переменная была единственной ссылкой на значение в любом месте, значение в конечном итоге будет удалено. В частности, в CPython сборщик мусора построен поверх подсчета ссылок. Таким образом, "в конечном итоге" означает "немедленно". * В других реализациях это обычно "довольно скоро".

Однако, если были другие ссылки на одно и то же значение, просто удалить одну из этих ссылок (будь то через del x, x = None, выходя из области, где существует x и т.д.), ничего не очищает. **


Здесь есть еще одна проблема. Я не знаю, что действительно делает модуль memory_profiler (предположительно этот), но описание (говорящее об использовании psutil) звучит так, будто оно измеряет ваши использование памяти из "снаружи".

Когда Python освобождает хранилище, он не всегда или даже обычно возвращает его в операционную систему. Он хранит "бесплатные списки" на нескольких уровнях, поэтому он может быстрее использовать память быстрее, чем если бы ей пришлось вернуться к ОС, чтобы попросить больше. В современных системах это редко бывает проблемой - если вам нужна память снова, хорошо, что у вас это было; если вы этого не сделаете, он будет выгружен, как только кому-то это понадобится, и никогда не будет выгружен обратно, так что там будет мало вреда.

(Кроме того, который я назвал "ОС" выше, на самом деле представляет собой абстракцию, состоящую из нескольких уровней, из библиотеки malloc через основную библиотеку C в ядро ​​/пейджер и по меньшей мере одну из этих уровней обычно имеют свои собственные бесплатные списки.)

Если вы хотите отслеживать использование памяти с внутренней точки зрения... ну, это довольно сложно. В Python 3.4 стало намного проще благодаря новому модулю tracemalloc. Существуют различные сторонние модули (например, heapy/guppy, Pympler, meliae), которые пытаются получить такую ​​же информацию с более ранними версиями, но это сложно, поскольку получение информации от различных распределителей и привязка этой информации к мусору коллекционер, был очень тяжелым до PEP 445.


* В некоторых случаях есть ссылки на значение... но только из других ссылок, которые сами недостижимы, возможно, в цикле. Это все еще считается "недостижимым" в отношении сборщика мусора, но не касается количества ссылок. Таким образом, у CPython также есть "детектор цикла", который работает так часто и находит циклы достижимых друг друга, но не достижимых значений, и очищает их.

** Если вы тестируете в интерактивной консоли, могут быть скрытые ссылки на ваши значения, которые трудно отслеживать, поэтому вы можете подумать, что избавились от последней ссылки, когда вы этого не сделали. В script всегда должно быть возможно, если не просто, разобраться в деталях. Модуль gc может помочь, как и отладчик. Но, конечно, оба они также дают вам новые способы добавления дополнительных скрытых ссылок.