2009-07-24 1 views
1

У меня есть массив, называемый x, размер которого равен 6 * sizeof (float). Я знаю, что объявление:Лучшие практики динамической и статической памяти с точки зрения чистоты и скорости

float x[6]; 

выделил бы 6 * sizeof (float) для x в стеке памяти. Однако, если я делаю следующее:

float *x; // in class definition 

x = new float[6]; // in class constructor 

delete [] x; // in class destructor 

Я бы выделить динамическую память 6 * SizeOf (флоат) х. Если размер x не изменяется для времени жизни класса с точки зрения наилучшей практики для чистоты и скорости (я смутно вспоминаю, если не правильно, что операции с памятью стека быстрее, чем операции с динамической памятью), я должен убедиться что x является статически, а не динамически распределенной памятью? Заранее спасибо.

+1

Обратите внимание, что «статический» в контексте C++ означает нечто совершенно иное, чем «в стеке»! Я считаю, что официальный термин для переменных стека является «автоматическим», а переменные, выделенные кучей, берутся «из свободного хранилища». – xtofl

ответ

8

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

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

+0

Почему вы используете слово «статически» в этом контексте? Это означает нечто совершенно иное, чем «на стеке» ... – xtofl

+0

(о, я вижу, это в вопросе ...) – xtofl

+0

@xtofl: Да, это не был удачный термин для использования здесь. Исправлена. – sharptooth

1

Да, объявление массива статически выполняется быстрее.

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

0

Композиция более эффективна, быстрее, снижает объем памяти и уменьшает фрагментацию памяти.

Вы могли бы сделать что-то вроде этого:

template <int SZ = 6> 
class Whatever { 
    ... 
    float floats[SZ]; 
}; 
0

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

0

Если yo распределить arraty статически, будет только один экземпляр этого. Точка использования класса заключается в том, что вы хотите несколько экземпляров. Нет необходимости распределять массив динамически вообще:

class A { 
    ... 
    private: 
     float x[8]; 
}; 

- это то, что вы хотите.

+0

«Если вы выделите массив статически, то будет только один экземпляр.Точка использования класса заключается в том, что вы хотите иметь несколько экземпляров ». - Хау? Будет массив для каждого экземпляра его объекта независимо от того, был ли он динамически выделен в конструкторе класса или статически выделен как переменная-член. – hobodave

+0

@ hobodave: Это неверно. Существует разница между распределением объектов в стеке и статическими объектами внутри класса. То, что Neil ссылается, является вторым. Тогда будет только один экземпляр массива, независимо от количества экземпляров класса . – Naveen

+1

@hobodave. Независимо от того, где появляется ikt, статическая переменная omly когда-либо имеет один экземпляр. – 2009-07-24 08:09:56

2

Данные TBH в стеке обычно находятся в кеше и, следовательно, быстрее. Однако, если вы динамически выделяете что-то один раз, а затем регулярно его используете, он также будет кэшироваться и, следовательно, очень быстро.

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

3

Использование элемента массива будет более чистым (более кратким, менее подверженным ошибкам) ​​и быстрее, поскольку нет необходимости вызывать функции выделения и освобождения. Вы также будете стремиться улучшить «местность ссылок» для распределяемой структуры.

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

0

Есть несколько переменных в игре здесь:

  1. Размер массива по сравнению с размером стека: размеры стеков достаточно малы по сравнению со свободным магазине (например, 1 МБ ДО 30Мб). Большие куски в стеке приведет к переполнению стека

  2. Количество массивов вам необходимо: большое количество небольших массивов

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

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

1

Статическое распределение не быстрее (нет необходимости просить памяти) и нет никакого способа, вы забудете удалить его или удалить его с неправильным удаления оператора (удаление вместо удаления []).

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

  • просит памяти для размещения объектов (вызов к новому оператору). Если памяти нет, новый оператор будет генерировать исключение bad_alloc.
  • создания объектов с конструктором по умолчанию (также выполняется с помощью нового)
  • высвобождения памяти пользователем (путем удаления/удалить оператор []) - удаление будет вызывать объекта деструктор. Здесь пользователь может сделать много ошибок:
    • забудьте позвонить удалить - это приведет к памяти протеканию
    • вызова не правильно удалить оператор (например, удаление вместо удаления []) - плохие вещи будут происходить
    • вызов удалить дважды - плохие вещи могут случиться

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

Итак, если вы знаете свой размер на массиве во время компиляции, и вы не имеете значения в памяти (возможно, во время выполнения я буду использовать не записи в массиве), статический массив, очевидно, предпочтителен , Для динамических распределенных данных, которые он стоит искать умные указатели (here)

1

Не следует путать следующие случаи:

int global_x[6];  // an array with static storage duration 

struct Foo { 
    int *pointer_x;  // a pointer member in instance data 
    int member_x[6]; // an array in instance data 
    Foo() { 
     pointer_x = new int[6]; // a heap-allocated array 
    } 
    ~Foo() { delete[] pointer_x; } 
}; 

int main() { 
    int auto_x[6];   // an array on the stack (automatic variable) 
    Foo auto_f;    // a Foo on the stack 
    Foo *dyn_f = new Foo(); // a heap-allocated Foo. 
} 

Сейчас:

  • auto_f.member_x находится в стеке, потому что auto_f является в стеке.
  • (*dyn_f).member_x находится на куче, потому что *dyn_f находится на куче.
  • Для обоих объектов Foo pointer_x указывает на массив, выделенный для кучи.
  • global_x находится в некоторых разделах данных, которые ОС или среда выполнения создают каждый раз при запуске программы. Это может быть или не быть из той же кучи, что и динамические распределения, обычно это не имеет значения.

Таким образом, независимо от того, это он на куче или нет, member_x является лучшим выбором, чем pointer_x в том случае, когда длина всегда 6, потому что:

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

Причины предпочитать pointer_x:

  • Если вам нужно перераспределять в течение всего срока службы объекта.
  • Если для разных объектов потребуется другой размерный массив (возможно, на основе параметров конструктора).
  • Если объекты Foo будут помещены в стек, но массив настолько велик, что он не поместится в стек. Например, если у вас есть 1 МБ стека, то вы не можете использовать автоматические переменные, которые содержат int[262144].
0

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

Было много разработок в malloc/новых подпрограммах, предоставляемых операционной системой (например, libumem Solaris). Динамическое распределение памяти часто не является узким местом.

Смежные вопросы