Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как Python хранит данные в памяти
Python использует механизм управления памятью на основе объектов и ссылок. Каждый объект содержит метаданные и значение.
Структура объекта в памяти
Каждый объект Python состоит из трёх компонентов:
import sys
# 1. Тип объекта
obj = 42
print(type(obj)) # <class "int">
# 2. Счётчик ссылок (reference count)
print(sys.getrefcount(obj)) # количество ссылок на объект
# 3. Значение
print(obj) # 42
PyObject — базовая структура для всех объектов:
ob_refcnt— счётчик ссылок (для garbage collection)ob_type— указатель на объект типа (metaclass)- Дополнительные данные (зависит от типа)
Управление памятью: Reference Counting
Python использует подсчёт ссылок (reference counting) — основной механизм управления памятью.
import sys
a = []
print(sys.getrefcount(a)) # 2 (сама переменная + аргумент функции)
b = a # ещё одна ссылка
print(sys.getrefcount(a)) # 3
del b # удалили ссылку
print(sys.getrefcount(a)) # 2 снова
Когда счётчик ссылок падает до 0, объект немедленно удаляется из памяти.
Сборка мусора (Garbage Collection)
Однако reference counting не решает проблему циклических ссылок:
# Циклическая ссылка
class Node:
def __init__(self, value):
self.value = value
self.next = None
a = Node(1)
b = Node(2)
a.next = b
b.next = a # циклическая ссылка!
del a
del b
# Объекты остаются в памяти, так как друг на друга ссылаются!
Для этого Python имеет сборщик мусора (garbage collector), который периодически ищет и удаляет циклические ссылки.
import gc
# Принудительно запустить сборку мусора
gc.collect()
# Отключить/включить
gc.disable()
gc.enable()
Интернирование строк и небольших целых чисел
Python оптимизирует память через интернирование — переиспользование одного объекта для нескольких переменных:
# Небольшие целые числа (-5 до 256) интернируются
a = 5
b = 5
print(a is b) # True! Один и тот же объект в памяти
print(id(a) == id(b)) # True
# Для больших чисел — разные объекты
x = 257
y = 257
print(x is y) # False (в REPL может быть True, но в скрипте False)
# Строки тоже интернируются
s1 = "hello"
s2 = "hello"
print(s1 is s2) # True
Стек (Stack) и куча (Heap)
Python хранит:
- На стеке: локальные переменные (ссылки на объекты)
- На куче: сами объекты
def foo():
a = [1, 2, 3] # ссылка `a` на стеке, список на куче
b = a # ещё одна ссылка на тот же список
return b
result = foo() # переменная result указывает на список на куче
# Когда функция завершилась, `a` и `b` удалены со стека,
# но объект список остаётся, так как на него есть ссылка result
Практический пример
import sys
# 1. Создание объекта
my_list = [1, 2, 3]
print(f"ID объекта: {id(my_list)}")
print(f"Размер в памяти: {sys.getsizeof(my_list)} байт")
print(f"Счётчик ссылок: {sys.getrefcount(my_list)}")
# 2. Ещё одна ссылка
my_list_copy = my_list
print(f"После присваивания: {sys.getrefcount(my_list)}") # +1
# 3. Проверка идентичности
print(f"my_list is my_list_copy: {my_list is my_list_copy}") # True
# 4. Удаление ссылки
del my_list_copy
print(f"После del: {sys.getrefcount(my_list)}") # -1
Ключевые выводы
- Все данные хранятся как объекты на куче (heap)
- Переменные — это ссылки на объекты
- Reference counting автоматически удаляет объекты при нулевом числе ссылок
- Garbage collector избавляет от циклических ссылок
- Интернирование экономит память для маленьких объектов
- Понимание этого важно для оптимизации памяти и избежания утечек памяти