Когда лучше использовать стек вместо "кучи" и наоборот?

Как будто вы пытаетесь получить доступ к объекту, который является null. Рассмотрим ниже пример:

TypeA objA;

. В это время вы только что объявили этот объект, но не инициализировали или не инициализировали. И всякий раз, когда вы пытаетесь получить доступ к каким-либо свойствам или методам в нем, он будет генерировать NullPointerException, что имеет смысл.

См. Также этот пример:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
60
задан Sebastian Paaske Tørholm 29 January 2011 в 11:10
поделиться

8 ответов

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

58
ответ дан Eddie Deyo 24 November 2019 в 17:42
поделиться

Как показывает опыт, постарайтесь не создавать огромные объекты на стеке.

  • Создание объекта на стеке освобождает Вас от нагрузки запоминания к очистке (чтение удаляют), объект. Но создание слишком многих объектов на стеке увеличит возможности переполнения стека.
  • при использовании "кучи" для объекта Вы получаете столько же памяти, которую ОС может обеспечить, намного больше, чем стек, но с другой стороны необходимо удостовериться, что освободили память, когда Вы сделаны. Кроме того, создание слишком многих объектов слишком часто в "куче" будет иметь тенденцию фрагментировать память, которая в свою очередь будет влиять на производительность Вашего приложения.
31
ответ дан nullDev 24 November 2019 в 17:42
поделиться

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

int main()
{ 
   if (...)
   {
      int i = 0;
   }
   // I know that i is no longer needed here, so declaring i in the above block 
   // limits the scope appropriately
}

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

Object* CreateObject();

int main()
{
    Object* obj = CreateObject();
    // I can continue to manipulate object and I decide when I'm done with it

    // ..
    // I'm done
    delete obj;
    // .. keep going if you wish
    return 0;
}

Object* CreateObject()
{
   Object* returnValue = new Object();
   // ... do a bunch of stuff to returnValue
   return returnValue;
   // Note the object created via new here doesn't go away, its passed back using 
   // a pointer
}

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

Общие решения на более управляемых языках (C#, Java) должны реализовать сборку "мусора", таким образом, Вы не должны думать об удалении вещей. Однако это означает, что существует что-то в фоновом режиме, которое работает апериодическим образом для проверения данных "кучи". В нетривиальной программе это может стать довольно неэффективным, поскольку поток "сборки"мусора"" открывается и двигается с пыхтением далеко, ища данные, которые должны быть удалены, в то время как остальная часть Вашей программы заблокирована от выполнения.

В C++, наиболее распространенном, и лучше всего (по-моему), решение контакта с утечками памяти состоит в том, чтобы использовать интеллектуальный указатель. Наиболее распространенный из них повышение:: shared_ptr, который является ( ссылка рассчитала )

Так для воссоздания примера выше повышения:: shared_ptr CreateObject ();

int main()
{
    boost::shared_ptr<Object> obj = CreateObject();
    // I can continue to manipulate object and I decide when I'm done with it

    // ..
    // I'm done, manually delete
    obj.reset(NULL);
    // .. keep going if you wish
    // here, if you forget to delete obj, the shared_ptr's destructor will note
    // that if no other shared_ptr's point to this memory 
    // it will automatically get deleted.
    return 0;
}

boost::shared_ptr<Object> CreateObject()
{
   boost::shared_ptr<Object> returnValue(new Object());
   // ... do a bunch of stuff to returnValue
   return returnValue;
   // Note the object created via new here doesn't go away, its passed back to 
   // the receiving shared_ptr, shared_ptr knows that another reference exists
   // to this memory, so it shouldn't delete the memory
}
13
ответ дан Doug T. 24 November 2019 в 17:42
поделиться

Исключение из правила упомянуло, выше которого необходимо обычно использовать стек для локальных переменных, которые не нужны вне объема функции:

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

8
ответ дан Kluge 24 November 2019 в 17:42
поделиться

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

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

его никогда не лучший для использования "кучи"... просто неизбежной.:)

5
ответ дан jheriko 24 November 2019 в 17:42
поделиться

Этот вопрос связан (хотя не действительно простофиля) к , Какой и где стек и "куча" , который спросили пару несколько дней назад.

4
ответ дан Community 24 November 2019 в 17:42
поделиться

Используйте "кучу" для того, чтобы только выделить место для объектов во времени выполнения. Если Вы знаете размер во время компиляции, используйте стек. Вместо того, чтобы возвратить выделенные "куче" объекты из функции, передайте буфер в функцию для него для записи в. Тем путем буфер может быть выделен, где функция вызвана как массив или другая стековая структура.

, Чем меньше malloc () операторы Вы имеете, тем меньше возможностей для утечек памяти.

3
ответ дан Kyle Cronin 24 November 2019 в 17:42
поделиться

Вопрос плохо формируется.

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

стек быстр, потому что выделение является просто "инкрементом" по SP, и все "выделение" выполняется во время вызова функции, в которой Вы находитесь. "Куча" (или свободное хранилище) выделение/освобождение время больше дорогая и подверженная ошибкам.

-1
ответ дан ugasoft 24 November 2019 в 17:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: