Комментарии (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++ с умными указателями решает проблему автоматически.