← Назад к вопросам

Что такое out of memory в Python?

2.0 Middle🔥 141 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Out of Memory в Python

Out of Memory (OOM) — это состояние, когда приложение исчерпывает доступную оперативную память (RAM), и операционная система больше не может выделять дополнительную память для процесса. В Python это приводит к критическому отказу программы.

Когда происходит Out of Memory

OOM killer в Linux — процесс, который убивает приложения, когда система исчерпывает доступную память:

# Плохой пример — бесконечное выделение памяти
big_list = []
while True:
    big_list.append(list(range(1000000)))  # Добавляем по 8MB каждый раз
    # ОС убьёт этот процесс с сигналом SIGKILL

Типичные причины OOM

1. Утечки памяти (Memory Leaks):

# Глобальный список, который никогда не очищается
cache = []

def process_request(data):
    cache.append(data)  # Память растёт с каждым запросом
    return len(cache)

# Если это веб-приложение с миллионами запросов
# memory будет расти бесконечно

2. Большие структуры данных в памяти:

import sys

# Загрузка огромного файла в память целиком
with open("huge_file.csv", "r") as f:
    all_data = f.readlines()  # Весь файл (например, 100GB) в памяти

print(f"Size: {sys.getsizeof(all_data) / (1024**3)} GB")

3. Циклические ссылки без очистки:

class Node:
    def __init__(self):
        self.ref = None

root = Node()
root.ref = root  # Циклическая ссылка

# Объект не удаляется, пока не сработает garbage collector
del root  # Память может остаться занята временно

4. Множество объектов в памяти:

# Создание миллионов объектов без удаления
users = []
for i in range(100_000_000):
    users.append({"id": i, "data": "x" * 1000})
    # Каждый словарь занимает память
    # ~1GB использовано за несколько минут

Диагностика проблем с памятью

1. Мониторинг с использованием psutil:

import psutil
import os

process = psutil.Process(os.getpid())
mem_info = process.memory_info()

print(f"RSS (physical RAM): {mem_info.rss / (1024**2):.2f} MB")
print(f"VMS (virtual memory): {mem_info.vms / (1024**2):.2f} MB")

# Также можно отслеживать использование в процессе выполнения
for i in range(5):
    process.memory_percent()  # % от общей памяти
    print(f"Memory: {process.memory_info().rss / (1024**3):.2f} GB")

2. Профилирование с memory_profiler:

# Установка: pip install memory-profiler

# @profile декоратор показывает использование памяти для каждой строки
from memory_profiler import profile

@profile
def my_function():
    a = [i for i in range(1000000)]
    b = [i * 2 for i in a]
    return sum(b)

my_function()

Вывод:

Line #    Mem usage    Increment  Line Contents
     5     38.5 MiB      0.0 MiB   def my_function():
     6     46.2 MiB      7.7 MiB       a = [i for i in range(1000000)]
     7     53.9 MiB      7.7 MiB       b = [i * 2 for i in a]
     8     53.9 MiB      0.0 MiB       return sum(b)

3. Анализ объектов с objgraph:

import objgraph

# Показать самые частые типы объектов
objgraph.show_most_common_types(limit=10)

# Отслеживать утечки
objgraph.show_growth(limit=3)

# Найти утечки между снимками
objgraph.show_refs([obj], max_depth=3)

Стратегии предотвращения OOM

1. Обработка данных потоком (Streaming):

# Плохо — весь файл в памяти
with open("large_file.csv", "r") as f:
    data = f.readlines()

# Хорошо — обработка строка за строкой
with open("large_file.csv", "r") as f:
    for line in f:  # Итератор, не загружает весь файл
        process_line(line)

2. Использование генераторов вместо списков:

# Плохо — создаёт весь список в памяти
def get_numbers():
    return [i for i in range(1_000_000_000)]  # Огромный список

# Хорошо — генератор, ленивые вычисления
def get_numbers():
    for i in range(1_000_000_000):
        yield i  # Возвращает по одному значению

for num in get_numbers():
    print(num)  # Каждое значение создаётся на лету

3. Явная очистка памяти:

import gc

large_list = list(range(10_000_000))
print(f"Memory before: {process.memory_info().rss / (1024**2):.2f} MB")

# Очистка переменной
del large_list

# Принудительная очистка мусора
gc.collect()
print(f"Memory after: {process.memory_info().rss / (1024**2):.2f} MB")

4. Ограничение размера кэша:

from functools import lru_cache

# maxsize ограничивает размер кэша
@lru_cache(maxsize=128)
def expensive_function(n):
    return n ** 2

# Для больших наборов данных:
from collections import OrderedDict

class LimitedCache:
    def __init__(self, max_size=1000):
        self.cache = OrderedDict()
        self.max_size = max_size
    
    def set(self, key, value):
        if key in self.cache:
            del self.cache[key]  # Переместить в конец
        self.cache[key] = value
        if len(self.cache) > self.max_size:
            self.cache.popitem(last=False)  # Удалить самый старый

5. Использование контекстных менеджеров:

# Файл автоматически закроется и освободит ресурсы
with open("file.txt", "r") as f:
    data = f.read()
# f уже закрыт, память освобождена

# Классический способ (неправильный)
f = open("file.txt", "r")
data = f.read()
# f остаётся открытым, пока не будет сборка мусора

Что происходит при OOM в Docker и Kubernetes

# Контейнер может быть убит OOM killer
# В Kubernetes подобные контейнеры перезагружаются

import os
import psutil

def monitor_memory():
    # Получить лимиты контейнера
    with open("/sys/fs/cgroup/memory/memory.limit_in_bytes") as f:
        limit = int(f.read())
    
    current_memory = psutil.virtual_memory().used
    percent = (current_memory / limit) * 100
    
    if percent > 90:
        print(f"WARNING: {percent:.1f}% of container memory used")

Практические советы

  • Используйте генераторы для больших наборов данных
  • Профилируйте память перед production
  • Устанавливайте лимиты памяти в контейнерах
  • Мониторьте использование памяти в production
  • Избегайте циклических ссылок и утечек
  • Используйте слабые ссылки (weakref) если необходимо

Out of Memory — это критическое состояние, которое требует профилактики, мониторинга и правильного дизайна приложения для предотвращения потери данных и сбоев в production.