Similar presentations:
Urok_16_Ukazateli_Dinamicheski_raspredelyaemaya_pamyat_v_Python
1. Указатели. Динамически распределяемая память в Python.
Цели:1.Понять фундаментальную концепцию указателя и работы с памятью.
2.Узнать, как Python реализует эти концепции через механизм ссылок.
3.Научиться создавать и управлять динамическими структурами данных.
4.Освоить принципы работы сборщика мусора (Garbage Collector).
2. Введение. Память программы и необходимость указателей
• Где хранятся переменные и данные, с которыми работаетпрограмма?
3. Введение. Память программы и необходимость указателей
• Оперативная память (RAM) — это рабочее пространствопрограммы. Её можно представить как огромный массив
пронумерованных ячеек (байтов). Каждая ячейка имеет
свой уникальный адрес — число, обозначающее её
положение в памяти.
4. Введение. Память программы и необходимость указателей
Когда вы создаёте переменную:x = 10
Интерпретатор Python:
1. Выделяет где-то в памяти область для хранения целого числа 10.
2. Создаёт связь между именем x и адресом этой области памяти.
3. Говорит: "Имя x теперь указывает на ячейку, где лежит значение 10".
5. Введение. Память программы и необходимость указателей
• Проблема: Жёсткое выделение памяти при компиляции(как в языках C/Pascal) негибко. Что, если нам нужно
создать массив, размер которого заранее неизвестен
(зависит от ввода пользователя, чтения файла)? Нужен
механизм для динамического запроса и освобождения
памяти во время выполнения программы.
• Решение: Указатели и динамическая память.
6. Что такое указатель? Описание и основные понятия
Указатель (pointer) — это переменная, значением которой являетсяадрес памяти другой переменной или объекта. Указатель не хранит полезные
данные (число, строку), он хранит "ссылку" на то место, где эти данные находятся.
Аналогия:
• Переменная (x = 10) — это бумажный стикер с названием "x", приклеенный
прямо на коробку, в которой лежит число 10.
• Указатель (p = &x) — это стикер с названием "p", приклеенный на отдельный
листок. На этом листке написано: "Иди к коробке с адресом 0xFFA1" (где и лежит
число 10).
• Важнейший момент для Python: В синтаксисе Python нет явных указателей в
стиле C/C++ (с операторами * и &). Вместо этого Python повсеместно использует
механизм ссылок (references), который является высокоуровневой и безопасной
7. В Python каждая переменная — это ссылка (имя), привязанная к объекту в памяти!!!
• Доказательство: оператор id() и функция is• Функция id(object) возвращает "идентификатор" объекта. В
реализации CPython это и есть адрес памяти объекта (в
виде целого числа).
• Оператор is проверяет, ссылаются ли две переменные на
один и тот же объект в памяти (т.е., сравнивает
идентификаторы).
8.
Вывод: Присваивание b = a не создаёт копию списка. Оно копируетссылку (адрес). Теперь две переменные (a и b) являются "указателями"
на один блок памяти.
9. Изменяемые vs. Неизменяемые типы. Важность для "указателей"
Изменяемые vs. Неизменяемыетипы. Важность для "указателей"
Поведение ссылок в Python сильно зависит от типа объекта.
• Неизменяемые (immutable) типы: int, float, str, tuple, bool, bytes,
frozenset.
• Объект такого типа нельзя изменить после создания.
• При "изменении" создаётся новый объект в памяти, и ссылка
перенаправляется на него.
10. Изменяемые vs. Неизменяемые типы. Важность для "указателей"
Изменяемые vs. Неизменяемые типы.Важность для "указателей"
11. Изменяемые vs. Неизменяемые типы. Важность для "указателей"
Изменяемые vs. Неизменяемые типы.Важность для "указателей"
• Изменяемые (mutable) типы: list, dict, set, bytearray, объекты
пользовательских классов.
• Объект можно изменить "на месте", не создавая новый.
• Все ссылки на этот объект "увидят" изменения.
12. Изменяемые vs. Неизменяемые типы. Важность для "указателей"
Изменяемые vs. Неизменяемые типы.Важность для "указателей"
Практический смысл: При передаче изменяемых объектов в
функции будьте осторожны — функция может изменить ваш
оригинальный объект.
13.
def modify(data):data.append("изменено") # Изменяет объект по ссылке
items = [1, 2, 3]
modify(items)
print(items) # [1, 2, 3, 'изменено'] ! Оригинал изменён.
14. Динамически распределяемая память. Куча (Heap)
Память программы условно делится на области:Стек (Stack): Быстрая память для локальных переменных функций. Управляется
автоматически.
Куча (Heap): Большая область динамической памяти. Выделение и
освобождение происходит во время выполнения программы по запросу
разработчика (или интерпретатора).
В Python, когда вы пишете x = [] или y = MyClass(), объект создаётся в
динамической памяти (куче). Переменная x или y (живущая, например, в
стеке) хранит только ссылку на этот объект в куче.
Динамическое распределение памяти — это процесс запроса у операционной
системы памяти из кучи во время работы программы.
15. Создание и удаление динамических переменных в Python
• В Python создание динамических объектов происходитнеявно и просто. Любое создание сложного объекта
(списка, словаря, экземпляра класса) — это выделение
динамической памяти.
16.
# Динамическое создание объектов (память выделяется в куче)dynamic_list = []
# Пустой список
dynamic_dict = {}
# Пустой словарь
import random
random_data = [random.randint(1, 100) for _ in range(1000)] # Список на 1000
элементов
# Размер memory выделяется динамически под нужное количество
элементов.
class Node:
def __init__(self, value):
self.value = value
self.next = None
node1 = Node(10) # Динамически создан объект-узел
node2 = Node(20)
node1.next = node2 # Связывание узлов ссылками -> основа структур данных
(списки, деревья)
17. Удаление. Сборка мусора (Garbage Collection)
• Ключевая проблема динамической памяти: Кто должен освобождатьпамять, когда объект больше не нужен?
• В языках без автоматического управления (C/C++): Программист
делает это вручную (free, delete). Ошибки ведут к утечкам памяти или
повреждению данных.
18. Удаление. Сборка мусора (Garbage Collection)
• Основной механизм — подсчёт ссылок (ReferenceCounting).
• Циклический сборщик мусора (Cycle Collector).
• Явное удаление
19.
• Основной механизм — подсчёт ссылок (ReferenceCounting).
• У каждого объекта есть счётчик, который увеличивается, когда
на него создаётся новая ссылка, и уменьшается, когда ссылка
удаляется или перенаправляется.
a = [1,2] # Счётчик ссылок для объекта [1,2] = 1
b = a # Счётчик ссылок для объекта [1,2] = 2
a = None # Убираем одну ссылку. Счётчик = 1.
b = None # Убираем последнюю ссылку. Счётчик = 0.
# Как только счётчик достигает 0, память объекта МОЖЕТ быть
немедленно освобождена.
20. Циклический сборщик мусора (Cycle Collector).
• Решает проблему циклических ссылок, когда два объектассылаются друг на друга, но на них уже нет внешних ссылок.
Счётчик ссылок никогда не станет нулевым.
class Node:
•Циклический сборщик
pass
периодически запускается, находит
node1 = Node() # RefCount = 1
такие изолированные циклы и
node2 = Node() # RefCount = 1
node1.ref = node2 # RefCount(node2) = 2 удаляет их.
node2.ref = node1 # RefCount(node1) = 2
# Удаляем внешние ссылки
node1 = None # RefCount(node1) = 1 (всё ещё есть ссылка из node2.ref)
node2 = None # RefCount(node2) = 1 (всё ещё есть ссылка из node1.ref)
# Объекты стали недостижимы, но их счётчики не нулевые! Утечка в
классической схеме.
21. Явное удаление
del variable_name — оператор удаляет ссылку, а не объект. Он уменьшает счётчикссылок на объект.
• big_data = [i for i in range(10**7)] # Создали огромный список
• # Работаем с big_data...
• del big_data # Удалили ссылку. Если других ссылок не было, счётчик = 0
-> память освободится.
gc.collect() — принудительный запуск циклического сборщика мусора
(модуль import gc). Используется редко, в особых случаях для
оптимизации.