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

Что такое куча?

2.0 Middle🔥 171 комментариев
#Структуры данных и алгоритмы

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

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

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

Куча (Heap) в программировании

Куча (heap) — это динамически управляемая область памяти, где выделяются объекты во время выполнения программы. Размер памяти определяется в runtime, и программист отвечает за освобождение памяти после использования (в C/C++ без умных указателей).

Куча vs Стек (Stack)

СвойствоСтекКуча
РазмерОграничен, обычно ~1-8 MBБольшой, может быть несколько GB
ВыделениеАвтоматическое (при объявлении)Явное (new, malloc)
ОсвобождениеАвтоматическое (при выходе из области)Явное (delete, free)
СкоростьОчень быстро (простой указатель)Медленнее (работа с allocator)
ФрагментацияНетМожет быть
Порядок выделенияLIFO (Last In First Out)Произвольный

Пример на C++

Стек — автоматическое управление:

void func() {
    int x = 5;              // Выделяется на стеке
    std::vector<int> arr;   // Выделяется на стеке
}  // x и arr автоматически удаляются при выходе из функции

Куча — явное управление:

void func() {
    int* p = new int(5);           // Выделяется на куче, указатель на стеке
    std::vector<int>* arr = new std::vector<int>();
    
    // ... работаем с p и arr ...
    
    delete p;      // Вручную освобождаем память
    delete arr;    // Вручную освобождаем память
}  // Если забыли delete — УТЕЧКА ПАМЯТИ!

Проблема: утечка памяти

void bad_func() {
    int* ptr = new int(42);  // Выделяем память на куче
    std::cout << *ptr;
    // Забыли delete — память никогда не будет освобождена!
    // Это утечка памяти (memory leak)
}

// Если функция вызывается миллион раз, программа исчерпает всю оперативную память

Modern C++ решение: умные указатели

std::unique_ptr — исключительное владение:

void good_func() {
    std::unique_ptr<int> ptr(new int(42));  // или std::make_unique<int>(42)
    std::cout << *ptr;
    // ptr автоматически удалится при выходе из области
}  // Никакой утечки! RAII паттерн

std::shared_ptr — совместное владение:

void func() {
    std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
    std::shared_ptr<int> ptr2 = ptr1;  // Обе копии указывают на один объект
    
    std::cout << ptr1.use_count();  // 2 (два владельца)
}  // При выходе из области, оба указателя удалятся, и память освобождится

Структура кучи

Куча организована сложнее, чем стек:

// При выделении
int* arr = new int[1000];  // Allocator выделяет блок памяти
// Метаданные:      | размер | данные (1000 int) |
// В памяти:        |--------|-------------------|

// При удалении
delete[] arr;  // Allocator использует метаданные для освобождения нужного размера

Фрагментация кучи

// Последовательные выделение и освобождение
void* p1 = malloc(1000);  // Блок A (1000 байт)
void* p2 = malloc(1000);  // Блок B (1000 байт)
void* p3 = malloc(1000);  // Блок C (1000 байт)

free(p2);  // Освобождаем средний блок

// Куча теперь: [A: занято][B: свободно][C: занято]
// Если нам нужно 500 байт подряд, мы сможем выделить из B
// Но если нам нужно 2000 байт подряд, мы не сможем, хотя всего свободно >2000!
// Это ФРАГМЕНТАЦИЯ

Когда использовать кучу?

Используй кучу, когда:

  • Размер данных заранее неизвестен (динамические массивы)
  • Нужна большая память (стек ограничен)
  • Объект должен жить дольше, чем текущая область видимости
  • Работа с полиморфизмом (virtual функции часто требуют кучи)
// Размер известен в compile-time → стек
int arr[100];  // Стек

// Размер неизвестен в runtime → куча
int n = 1000;
int* arr = new int[n];  // Куча

Используй стек, когда:

  • Размер известен в compile-time
  • Объект локален и коротко живёт
  • Нужна максимальная производительность

Типичная структура программы в памяти

High Address
    ┌──────────────────┐
    │      Stack       │  (автоматические переменные, параметры, адреса возврата)
    │        ↓         │
    ├──────────────────┤
    │   (свободное)    │  (промежуток)
    ├──────────────────┤
    │      Heap        │  (new, malloc)
    │        ↑         │
    ├──────────────────┤
    │  Global/Static   │  (глобальные переменные, статические)
    ├──────────────────┤
    │      BSS         │  (неинициализированные глобальные)
    ├──────────────────┤
    │   Data segment   │  (инициализированные глобальные)
    ├──────────────────┤
    │   Text segment   │  (машинный код программы)
Low Address
    └──────────────────┘

Инструменты для отладки утечек

# Valgrind (Linux)
valgrind --leak-check=full ./program

# AddressSanitizer (gcc/clang)
g++ -fsanitize=address -g program.cpp -o program
./program

Куча — необходимый инструмент, но требует дисциплины в управлении памятью. Modern C++ с умными указателями решает проблему автоматически.

Что такое куча? | PrepBro