Подтвердить что ты не робот

Зачем вам когда-либо хотеть выделять память на кучу, а не на стек?

Возможный дубликат:
Когда лучше использовать стек вместо кучи и наоборот?

Я прочитал несколько других вопросов относительно кучи и стека, но они, похоже, больше сосредотачиваются на том, что делает куча/стек, а не на том, почему вы их используете.

Мне кажется, что распределение стека почти всегда будет предпочтительным, поскольку оно быстрее (просто перемещение указателя стека и поиск свободного места в куче), и вам не нужно вручную освобождать выделенную память, когда вы сделано с его помощью. Единственная причина, по которой я могу понять, использовать выделение кучи, - это то, что вы хотите создать объект в функции, а затем использовать его вне этой области видимости, поскольку выделенная память в стеке автоматически не распределяется после возврата из функции.

Существуют ли другие причины использования распределения кучи вместо распределения стека, о котором я не знаю?

4b9b3361

Ответ 1

Есть несколько причин:

  • Главное, что с распределением кучи у вас есть самый гибкий контроль над временем жизни объекта (от malloc/calloc до free);
  • Пространство стека обычно является более ограниченным ресурсом, чем пространство с кучей, по крайней мере, в конфигурациях по умолчанию;
  • Невозможность выделения кучного пространства может быть обработана изящно, в то время как неисполнение пространства стека часто невосстанавливается.

Без гибкого срока жизни объекта полезные структуры данных, такие как бинарные деревья и связанные списки, практически невозможно записать.

Ответ 2

  • Вы хотите, чтобы распределение выходило за вызов функции
  • Вы хотите сохранить пространство стека (которое обычно ограничено несколькими МБ).
  • Вы работаете с повторно локалируемой памятью (Win16, базы данных и т.д.) или хотите восстановить отказ от размещения.
  • Переменная длина. Вы можете подделывать это, но ваш код будет действительно неприятным.

Большой - # 1. Как только вы попадаете в какой-либо concurrency или IPС# 1, везде. Даже самые нетривиальные однопоточные приложения сложны для разработки без некоторого распределения кучи. Это было бы фактически фальсифицировать функциональный язык в C/С++.

Ответ 3

Итак, я хочу создать строку. Я могу сделать это в куче или в стеке. Попробуйте оба:

char *heap = malloc(14);
if(heap == NULL)
  {
    // bad things happened!
  }
strcat(heap, "Hello, world!");

И для стека:

char stack[] = "Hello, world!";

Итак, теперь у меня эти две строки в соответствующих местах. Позже я хочу сделать их дольше:

char *tmp = realloc(heap, 20);
if(tmp == NULL)
  {
    // bad things happened!
  }
heap = tmp;
memmove(heap + 13, heap + 7);
memcpy(heap + 7, "cruel ", 6);

И для стека:

// umm... What?

Это только одно преимущество, а другие упоминали о других преимуществах, но это довольно неплохо. С кучей мы можем хотя бы попытаться сделать наше выделенное пространство более крупным. Со стеклом мы застряли с тем, что у нас есть. Если нам нужно пространство для роста, мы должны объявить все это впереди, и все мы знаем, как это воняет, чтобы увидеть это:

char username[MAX_BUF_SIZE];

Ответ 4

Наиболее очевидное обоснование использования кучи - это когда вы вызываете функцию и нуждаетесь в возврате неизвестной длины. Иногда вызывающий может передать блок памяти и размер функции, но в других случаях это просто непрактично, особенно если возвращаемый материал является сложным (например, коллекция различных объектов с указателями, летающими вокруг и т.д.).

Ответ 5

Ограничения по размеру - это большой разбойник во многих случаях. Стек обычно измеряется в мегабайтах или даже килобайтах (что для всего в стеке), тогда как все современные ПК позволяют вам несколько гигабайт кучи. Поэтому, если вы собираетесь использовать большой объем данных, вам абсолютно нужна куча.

Ответ 6

просто добавить вы можете использовать alloca для выделения памяти в стеке, но опять же память в стеке ограничена, а также пространство существует только во время выполнения функции, это не значит, что все должно быть выделено на кучу. как и все дизайнерские решения, это также несколько сложно, следует использовать "разумную" комбинацию обоих.

Ответ 7

Помимо ручного управления временем жизни объекта (которое вы упомянули), другие причины использования кучи будут включать в себя:

  • Контроль времени выполнения объекта (как начального размера, так и размера "позже" во время выполнения программы).

Например, вы можете выделить массив определенного размера, который известен только во время выполнения.

С введением VLA (Variable Length Arrays) в C99 стало возможным выделять массивы фиксированного размера времени выполнения без использования кучи (это в основном реализация уровня "alloca" на уровне языка). Однако в других случаях вам все равно нужна куча даже на C99.

  • Контроль времени выполнения всего количества объектов.

Например, когда вы строите двоичную структуру дерева, вы не можете значительно выделить узлы дерева в стеке заранее. Вы должны использовать кучу, чтобы выделить их "по требованию".

  • Низкоуровневые технические соображения, как ограниченное пространство стека (другие уже упомянули об этом).

Если вам нужен большой, скажем, буфер ввода-вывода, даже на короткое время (внутри одной функции), имеет смысл запросить его из кучи вместо объявления большого автоматического массива.

Ответ 8

Переменные стека (часто называемые "автоматическими переменными" ) лучше всего использовать для вещей, которые вы всегда должны быть одинаковыми, и всегда быть маленькими.

int x;
char foo[32];

Являются ли все распределения стека, они также фиксируются во время компиляции.

Лучшая причина для распределения кучи заключается в том, что вы не можете всегда знать, сколько места вам нужно. Вы часто знаете об этом только после запуска программы. У вас может быть представление о ограничениях, но вы хотели бы использовать только то необходимое количество места.

Если вам нужно было прочитать в файле, который может быть от 1k до 50mb, вы не сделали бы этого: -

int readdata ( FILE * f ) {
  char inputdata[50*1024*1025];
  ...
  return x;
}

Это попытается выделить 50 МБ в стеке, который обычно терпит неудачу, так как стек обычно ограничен до 256 тыс. в любом случае.

Ответ 9

Стек и куча разделяют одно и то же "открытое" пространство памяти и должны будут в конечном итоге подойти к точке, где они встречаются, если вы используете весь сегмент памяти. Сохранение баланса между пространством, которое использует каждый из них, впоследствии будет амортизировано для распределения и де-распределения памяти меньшим асимптотическим значением.