Возможна ли утечка памяти в Python?
Приведите пожалуйста пример плохого кода на Python, содержащий утечку памяти. Я не очень хорошо понимаю что это такое, как такого можно "добиться". Разве сборщик мусора нужен нам не для того, чтобы утечек памяти не было?
Ответы (2 шт):
import matplotlib.pyplot as plt
import random, psutil
def png(x, y) -> None:
(fig, axs) = plt.subplots(1, 1, figsize=(17, 5))
axs.plot(x, y)
if __name__ == '__main__':
while True: # RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).
png(random.randint(1, 10), random.randint(1, 10))
print('memory % used:', psutil.virtual_memory()[2])
out:
memory % used: 57.9
...
memory % used: 58.0
...
memory % used: 58.4
...
memory % used: 58.9
...
memory % used: 60.7
...
В Python может быть утечка памяти если не использовать слабые ссылки при использовании циклических структур по типу связных списков. Хотя циклический сборщик мусора и должен следить за такими объектами, на практике, циклические объекты при неправильном удалении могут долго оставаться живыми. Например, если удалить голову у вышеупомянутого связного списка, то всё тело останется в памяти неосвобождённым, и доступа к нему не будет.
Простой пример:
import weakref
class Node:
def __init__(self, data):
self.prev = self.next = None
self.data = data
def __del__(self):
print(f"Сработал Деструктор {self.data}")
class DoubleLinkedList:
__slots__ = ("head", "tail",)
def __init__(self):
self.head = self.tail = None
def append(self, data):
newNode = Node(data)
if self.head is None:
self.head = self.tail = newNode
self.head.prev = None
self.tail.next = None
else:
self.tail.next = newNode
newNode.prev = weakref.ref(self.tail)
self.tail = newNode
self.tail.next = None
return self
obj = DoubleLinkedList()
obj.append(4).append(3).append(2).append(1)
del obj
input()
Вывод
Сработал Деструктор 4
Сработал Деструктор 3
Сработал Деструктор 2
Сработал Деструктор 1
Вывод если убрать weakref.ref
В данном примере используются слабые ссылки и при удалении объекта все узлы удалятся. Если же их не использовать, то все узлы останутся существовать. И доступ к ним навсегда исчезнет. Поэтому при использовании циклических объектов рекомендуется использовать слабые ссылки.