Какое распределение происходит быстрее? malloc против локальной переменной

Какой предпочтительный способ выделить память для функции, которая часто выделяет и освобождает память? Предположим, что эта функция вызывается примерно от 500 до 1000 раз в секунду на процессоре 1 ГГц.

(Пожалуйста, игнорируйте статические и глобальные переменные/распределение. Меня интересует только этот конкретный случай:)

void Test()
{
    ptr=malloc(512)   // 512 bytes
    ...
    free(ptr) 
}

ИЛИ

void Test()
{
     struct MyStruct localvar; // 512 byte sized structure
     ... 
}

Ответ 1

распределение локальных переменных в стеке быстрее, чем распределение кучи с malloc. Однако общее пространство стека ограничено (например, до нескольких мегабайт). Поэтому вы должны ограничить себя "маленькими" данными в локальном стеке. (а 512 байт на сегодняшний день невелики, но 256Kb будет слишком большим для локального распределения стека).

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

Но вызов malloc несколько тысяч раз в секунду должен быть безболезненным (IMHO типичный малогабаритный malloc занимает несколько десятков микросекунд).

Для вашего любопытства и за пределами мира C вам может быть интересна старая бумага A.Appel сбор мусора может быть быстрее, чем распределение стека (но, возможно, соображения производительности кэша могут ослабить это требование сегодня).

Ответ 2

Локальные переменные распределяются по существу "бесплатно", поэтому здесь нет конкурса, если нас интересует только производительность.

Однако:

  • выбор между локальной и распределенной кучей переменной обычно не является чем-то, что вы можете свободно решать без ограничений; обычно есть факторы, которые определяют выбор, поэтому ваш вопрос немного подозрительный, поскольку он, кажется, игнорирует эту проблему.
  • при распределении по стеку "свободна" по производительности, пространство в стеке может быть ограничено (хотя, конечно, 512 байт ничего)

Ответ 3

  • Это предпочтительный способ выделения памяти....
  • Какое распределение выполняется быстрее?

Вам нужен более быстрый способ или предпочтительный способ?

В любом случае, в случае, о котором вы упомянули, я думаю, что второй вариант:

struct MyStruct localvar;

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

Оптимизация

Кроме того, если вы делаете это для повышения производительности и оптимизации...

На моем ПК, используя malloc, чтобы выделять строки вместо объявления массива char из стека, дает мне отставание ~ 73 наносекунды за строку.

если вы скопировали 50 строк в своей программе: 4757142/50 = 95142 (и немного) прогонов вашей программы

Если я запускаю вашу программу 50 раз в день: 95142/50 = 1902 (и немного) дней

1902 дней = 5 1/5 лет

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

Ответ 4

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

Локальная переменная (на основе стека) потребует 0 дополнительных циклов - вы даже не увидите, где происходит распределение, поскольку функция будет распределять все локальные переменные за 1 цикл, просто перемещая указатель стека и освобождая все локальные переменные в 1 цикл, восстановив указатель стека. Неважно, есть ли у вас 1 или 1000 локальных переменных, "распределение" занимает одинаковое количество времени.

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

Мое правило: всегда используйте стек, если это возможно, вместо malloc/free или new/delete. В дополнение к более быстрой производительности вы получаете дополнительное преимущество: не беспокоиться о утечке памяти или утечки ресурсов. В C это просто означает забыть вызвать free(), но в исключениях С++ может испортить ваш день, если что-то выдает исключение, прежде чем вы вызываете delete. Если вы используете переменные стека, все это обрабатывается автоматически! Однако используйте стек только в том случае, если речь идет о "небольших" фрагментах памяти (байты и КБ), а не об огромных объектах (не МБ или ГБ!). Если вы все равно говорите об огромных объектах, вы больше не говорите о производительности, и вы, вероятно, не будете называть free/delete тем же вызовом функции.

Ответ 5

Распределение стека выполняется быстрее, чем malloc + free.

Распределение стека обычно измеряется в инструкциях, тогда как malloc + free может потребоваться несколько блокировок (в качестве одного из примеров того, почему это занимает много времени).

Ответ 6

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

Ответ 7

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