Потеря пространства или утечки памяти: Python

Я запутался в следующей ситуации, и, возможно, мой лексикон здесь не так, поэтому извиняйтесь.

Скажем, у нас есть кортеж, x = ('a', []) а затем мы делаем x = (x[0], [1, 2, 3]).

Поскольку новый кортеж ссылается на старый кортеж, мы не можем удалить старый объект tuple, но из-за этого старого объекта tuple мы используем только ссылку на x [0], мы теряем память как x [1] старого Объект кортежа не может быть доступен никем.

Является ли это истинным случаем утечки памяти; мы теряем память именно так, чтобы ссылки на новые кортежи имели смысл.

3 ответа

Вероятно, вы попадете на Python с языка, такого как C++, где переменные являются ячейками памяти, в которых хранятся значения. В Python значения хранятся где-то, о чем вам не нужно беспокоиться, а ваши переменные - это просто имена, которые ссылайтесь на эти значения. Невозможно сделать ссылку на переменную другой переменной * -you может заставить ссылаться на то же значение, что и на другую переменную, но это не проблема.

Например, в C++:

int x[] = {1, 2, 3};
int &y = x[0];

Здесь x - это ячейка памяти, достаточно большая для трех значений int, а y - ссылка на первое из этих местоположений. Итак, если x уйдет, а y еще жив, у вас будет болтливая ссылка, которая будет плохой. Но в Python:

x = [1, 2, 3]
y = x[0]

Здесь x - это имя для объекта list, три позиции которого являются именами трех разных объектов int хранящихся в другом месте, а y - просто другое имя для первого объекта int. Если x уходит, Python может освободить list, после чего он может освободить 2 и 3 объекта ** (потому что никто не ссылается на них), оставив только 1 объект позади.

Вот почему в Python нет "конструкторов копирования" ***. В C++ int z = x[0] создает новую ячейку памяти и неявно копирует int из x[0] в эту ячейку памяти; в Python, если вы явно не пишете что-то вроде z = copy.copy(x[0]), вы никогда ничего не копируете.

* Это не совсем так, если вы посмотрите, как ячейки закрытия работают под обложками.

** На самом деле, маленькие целые числа обычно обрабатываются специально и сохраняются навсегда, но не обращайте на них внимания.

*** Гораздо меньше операторы присваивания копий, перемещают конструкторы и переносят операторы присваивания.


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

>>> x = ('a', [])
>>> id(x)
4340112344 # The tuple
>>> id(x[0])
4339406128 # The character 'a'
>>> id(x[1])
4340109184 # An empty list
>>> x = (x[0], [1,2,3])
>>> id(x)
4340112488 # x refers to a new object
>>> id(x[0])
4339406128 # The character 'a'. The old tuple is not involved
>>> id(x[1])
4340199576 # A new list.

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


Небольшая логическая ошибка.

Строки Python неизменяемы.Когда вы это сделаете:

x = ('a', [])

а затем это:

x = (x[0], [1,2,3])

x[0] теперь является новой строкой, т.е. не привязанной к оригиналу. Поэтому GC может собирать исходный кортеж.

ВЫШЕ НЕВИДИМО !!!Acck !!!!!!!НЕЗАКОННАЯ ЛОГИКА !!!Нижний текст действителен для ВСЕХ типов !!!

Однако, если бы мы это сделали:

x = (x[1], 'Hi!')

исходный кортеж по-прежнему удаляется, хотя x[1] является ссылкой на список. Зачем? Поскольку список не привязан к кортежу. Эти два являются независимыми объектами. Таким образом, когда вы ссылаетесь на x[1], другие элементы, а также исходный кортеж могут быть безопасно удалены.

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

Таким образом, утечки памяти нет.

licensed under cc by-sa 3.0 with attribution.